Method overloading in php example


Method Overloading is a concept of Object Oriented Programming which helps in building the composite application in an easy way. Function overloading or method overloading is a feature that permits making creating several methods with a similar name that works differently from one another in the type of the input parameters it accepts as arguments.

The above concept is fine for other programming languages and it is called static polymorphic i.e method overloading.

Example

Let's understand through an example.

doTask(5,10);
?>

Output:

Error

Explanation:

This will generate an error since php will say you have declared this method twice.
But Other programming languages says , doTask($var1) and doTask($var1,$var2) are overloaded methods. To call the latter, two parameters must be passed, whereas the former requires only one parameter.
so this behavior i.e decision to call a function at coding time is known as static polymorphic i.e method overloading.

Let's discuss how to achieve method overloading related to PHP5.In the case of PHP, we have to utilize PHP's magic methods __call() to achieve method overloading.

In PHP overloading means the behavior of method changes dynamically according to the input parameter. In this tutorial, we will understand those perceptions. Let's discuss the __call() method.

__call():

If a class execute __call(), then if an object of that class is called with a method that doesn't exist then__call() is called instead of that method.

Example

Let's understand method overloading with an example.

area(3);
   $rect = new Shape();
   echo $rect->area(8,6);
?>

Output:

9.426
48

Explanation:

Here area() method is created dynmically and executed with the help of magic method __call() and it's behaviour changes according to pass of parametrs as object.

Method overloading in php example

Updated on 31-Dec-2019 08:29:38

  • Related Questions & Answers
  • What is method overloading in C#?
  • What is method overloading in Java?
  • PHP Overloading
  • What is runtime polymorphism or dynamic method overloading?
  • What is the difference between method overloading and method hiding in Java?
  • What is the difference between method overloading and method overriding in Java?
  • What is overloading in C#?
  • What is Overloading in Java?
  • Method overloading in Java
  • What is constructor overloading in Java?
  • What is function overloading in JavaScript?
  • What is overloading? What happens if we overload a main method in java?
  • Function Overloading and Overriding in PHP
  • Using Method Overloading in Java
  • What is overloading a unary operator in C++?

Overloading in PHP provides means to dynamically create properties and methods. These dynamic entities are processed via magic methods one can establish in a class for various action types.

The overloading methods are invoked when interacting with properties or methods that have not been declared or are not visible in the current scope. The rest of this section will use the terms inaccessible properties and inaccessible methods to refer to this combination of declaration and visibility.

All overloading methods must be defined as public.

Note:

None of the arguments of these magic methods can be passed by reference.

Note:

PHP's interpretation of overloading is different than most object-oriented languages. Overloading traditionally provides the ability to have multiple methods with the same name but different quantities and types of arguments.

Property overloading

public __set(string $name, mixed $value): void

public __get(string $name): mixed

public __isset(string $name): bool

public __unset(string $name): void

__set() is run when writing data to inaccessible (protected or private) or non-existing properties.

__get() is utilized for reading data from inaccessible (protected or private) or non-existing properties.

__isset() is triggered by calling isset() or empty() on inaccessible (protected or private) or non-existing properties.

__unset() is invoked when unset() is used on inaccessible (protected or private) or non-existing properties.

The $name argument is the name of the property being interacted with. The __set() method's $value argument specifies the value the $name'ed property should be set to.

Property overloading only works in object context. These magic methods will not be triggered in static context. Therefore these methods should not be declared static. A warning is issued if one of the magic overloading methods is declared static.

Note:

The return value of __set() is ignored because of the way PHP processes the assignment operator. Similarly, __get() is never called when chaining assignments together like this:

 $a = $obj->b = 8; 

Note:

PHP will not call an overloaded method from within the same overloaded method. That means, for example, writing return $this->foo inside of __get() will return null and raise an E_WARNING if there is no foo property defined, rather than calling __get() a second time. However, overload methods may invoke other overload methods implicitly (such as __set() triggering __get()).

Example #1 Overloading properties via the __get(), __set(), __isset() and __unset() methods

class PropertyTest
{
    
/**  Location for overloaded data.  */
    
private $data = array();/**  Overloading not used on declared properties.  */
    
public $declared 1;/**  Overloading only used on this when accessed outside the class.  */
    
private $hidden 2;

    public function

__set($name$value)
    {
        echo 
"Setting '$name' to '$value'\n";
        
$this->data[$name] = $value;
    }

    public function

__get($name)
    {
        echo 
"Getting '$name'\n";
        if (
array_key_exists($name$this->data)) {
            return 
$this->data[$name];
        }
$trace debug_backtrace();
        
trigger_error(
            
'Undefined property via __get(): ' $name .
            
' in ' $trace[0]['file'] .
            
' on line ' $trace[0]['line'],
            
E_USER_NOTICE);
        return 
null;
    }

    public function

__isset($name)
    {
        echo 
"Is '$name' set?\n";
        return isset(
$this->data[$name]);
    }

    public function

__unset($name)
    {
        echo 
"Unsetting '$name'\n";
        unset(
$this->data[$name]);
    }
/**  Not a magic method, just here for example.  */
    
public function getHidden()
    {
        return 
$this->hidden;
    }
}

echo

"
\n";$obj = new PropertyTest;$obj->1;
echo 
$obj->"\n\n";var_dump(isset($obj->a));
unset(
$obj->a);
var_dump(isset($obj->a));
echo 
"\n";

echo

$obj->declared "\n\n";

echo

"Let's experiment with the private property named 'hidden':\n";
echo 
"Privates are visible inside the class, so __get() not used...\n";
echo 
$obj->getHidden() . "\n";
echo 
"Privates not visible outside of class, so __get() is used...\n";
echo 
$obj->hidden "\n";
?>

The above example will output:

Setting 'a' to '1'
Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'


Notice:  Undefined property via __get(): hidden in  on line 70 in  on line 29

Method overloading

public __call(string $name, array $arguments): mixed

public static __callStatic(string $name, array $arguments): mixed

__call() is triggered when invoking inaccessible methods in an object context.

__callStatic() is triggered when invoking inaccessible methods in a static context.

The $name argument is the name of the method being called. The $arguments argument is an enumerated array containing the parameters passed to the $name'ed method.

Example #2 Overloading methods via the __call() and __callStatic() methods

class MethodTest
{
    public function 
__call($name$arguments)
    {
        
// Note: value of $name is case sensitive.
        
echo "Calling object method '$name' "
             
implode(', '$arguments). "\n";
    }

    public static function

__callStatic($name$arguments)
    {
        
// Note: value of $name is case sensitive.
        
echo "Calling static method '$name' "
             
implode(', '$arguments). "\n";
    }
}
$obj = new MethodTest;
$obj->runTest('in object context');MethodTest::runTest('in static context');
?>

The above example will output:

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context

theaceofthespade at gmail dot com

10 years ago

A word of warning!  It may seem obvious, but remember, when deciding whether to use __get, __set, and __call as a way to access the data in your class (as opposed to hard-coding getters and setters), keep in mind that this will prevent any sort of autocomplete, highlighting, or documentation that your ide mite do.

Furthermore, it beyond personal preference when working with other people.  Even without an ide, it can be much easier to go through and look at hardcoded member and method definitions in code, than having to sift through code and piece together the method/member names that are assembled in __get and __set.

If you still decide to use __get and __set for everything in your class, be sure to include detailed comments and documenting, so that the people you are working with (or the people who inherit the code from you at a later date) don't have to waste time interpreting your code just to be able to use it.

Anonymous

6 years ago

First off all, if you read this, please upvote the first comment on this list that states that “overloading” is a bad term for this behaviour. Because it REALLY is a bad name. You’re giving new definition to an already accepted IT-branch terminology.

Second, I concur with all criticism you will read about this functionality. Just as naming it “overloading”, the functionality is also very bad practice. Please don’t use this in a production environment. To be honest, avoid to use it at all. Especially if you are a beginner at PHP. It can make your code react very unexpectedly. In which case you MIGHT be learning invalid coding!

And last, because of __get, __set and __call the following code executes. Which is abnormal behaviour. And can cause a lot of problems/bugs.

class BadPractice {
 
// Two real properties
 
public $DontAllowVariableNameWithTypos = true;
  protected
$Number = 0;
 
// One private method
 
private function veryPrivateMethod() { }
 
// And three very magic methods that will make everything look inconsistent
  // with all you have ever learned about PHP.
 
public function __get($n) {}
  public function
__set($n, $v) {}
  public function
__call($n, $v) {}
}
// Let's see our BadPractice in a production environment!
$UnexpectedBehaviour = new BadPractice;// No syntax highlighting on most IDE's
$UnexpectedBehaviour->SynTaxHighlighting = false;// No autocompletion on most IDE's
$UnexpectedBehaviour->AutoCompletion = false;// Which will lead to problems waiting to happen
$UnexpectedBehaviour->DontAllowVariableNameWithTyphos = false; // see if below

// Get, Set and Call anything you want!

$UnexpectedBehaviour->EveryPosibleMethodCallAllowed(true, 'Why Not?');// And sure, why not use the most illegal property names you can think off
$UnexpectedBehaviour->{'100%Illegal+Names'} = 'allowed';// This Very confusing syntax seems to allow access to $Number but because of
// the lowered visibility it goes to __set()
$UnexpectedBehaviour->Number = 10;// We can SEEM to increment it too! (that's really dynamic! :-) NULL++ LMAO
$UnexpectedBehaviour->Number++;// this ofcourse outputs NULL (through __get) and not the PERHAPS expected 11
var_dump($UnexpectedBehaviour->Number);// and sure, private method calls LOOK valid now!
// (this goes to __call, so no fatal error)
$UnexpectedBehaviour->veryPrivateMethod();// Because the previous was __set to false, next expression is true
// if we didn't had __set, the previous assignment would have failed
// then you would have corrected the typho and this code will not have
// been executed. (This can really be a BIG PAIN)
if ($UnexpectedBehaviour->DontAllowVariableNameWithTypos) {
 
// if this code block would have deleted a file, or do a deletion on
  // a database, you could really be VERY SAD for a long time!
 
$UnexpectedBehaviour->executeStuffYouDontWantHere(true);
}
?>

egingell at sisna dot com

15 years ago

Small vocabulary note: This is *not* "overloading", this is "overriding".

Overloading: Declaring a function multiple times with a different set of parameters like this:
function foo($a) {
    return
$a;
}

function

foo($a, $b) {
    return
$a + $b;
}

echo

foo(5); // Prints "5"
echo foo(5, 2); // Prints "7"?>

Overriding: Replacing the parent class's method(s) with a new method by redeclaring it like this:
class foo {
    function new(
$args) {
       
// Do something.
   
}
}

class

bar extends foo {
    function new(
$args) {
       
// Do something different.
   
}
}
?>

pogregoire##live.fr

6 years ago

It is important to understand that encapsulation can be very easily violated in PHP. for example :
class Object{

}

$Object = new Object();
$Objet->barbarianProperties  = 'boom';

var_dump($Objet);// object(Objet)#1 (1) { ["barbarianProperties"]=> string(7) "boom" }

Hence it is possible to add a propertie out form the class definition.
It is then a necessity in order to protect encapsulation to introduce __set() in the class :

class Objet{
    public function __set($name,$value){
        throw new Exception ('no');
    }
}

Anonymous

7 years ago

Using magic methods, especially __get(), __set(), and __call() will effectively disable autocomplete in most IDEs (eg.: IntelliSense) for the affected classes.

To overcome this inconvenience, use phpDoc to let the IDE know about these magic methods and properties: @method, @property, @property-read, @property-write.

/**
* @property-read name
* @property-read price
*/
class MyClass
{
    private $properties = array('name' => 'IceFruit', 'price' => 2.49)

        public function __get($name)
    {
        return $this->properties($name);
    }
}

cottton at i-stats dot net

8 years ago

Actually you dont need __set ect imo. 
You could use it to set (pre-defined) protected (and in "some" cases private) properties . But who wants that?
(test it by uncommenting private or protected)
(pastebin because long ...) => http://pastebin.com/By4gHrt5

Ant P.

13 years ago

Be extra careful when using __call():  if you typo a function call somewhere it won't trigger an undefined function error, but get passed to __call() instead, possibly causing all sorts of bizarre side effects.
In versions before 5.3 without __callStatic, static calls to nonexistent functions also fall through to __call!
This caused me hours of confusion, hopefully this comment will save someone else from the same.

gabe at fijiwebdesign dot com

7 years ago

Note that you can enable "overloading" on a class instance at runtime for an existing property by unset()ing that property.

eg:

class Test {

    public

$property1;

    public function

__get($name)
    {
        return
"Get called for " . get_class($this) . "->\$$name \n";
    }

}

?>

The public property $property1 can be unset() so that it can be dynamically handled via __get().

$Test = new Test();
unset(
$Test->property1); // enable overloading
echo $Test->property1; // Get called for Test->$property1
?>

Useful if you want to proxy or lazy load properties yet want to have documentation and visibility in the code and debugging compared to __get(), __isset(), __set() on non-existent inaccessible properties.

navarr at gtaero dot net

12 years ago

If you want to make it work more naturally for arrays $obj->variable[] etc you'll need to return __get by reference.

class Variables
{
        public function
__construct()
        {
                if(
session_id() === "")
                {
                       
session_start();
                }
        }
        public function
__set($name,$value)
        {
               
$_SESSION["Variables"][$name] = $value;
        }
        public function &
__get($name)
        {
                return
$_SESSION["Variables"][$name];
        }
        public function
__isset($name)
        {
                return isset(
$_SESSION["Variables"][$name]);
        }
}
?>

jstubbs at work-at dot co dot jp

16 years ago

->foo['bar'] = 'baz'; ?>

When overriding __get and __set, the above code can work (as expected) but it depends on your __get implementation rather than your __set. In fact, __set is never called with the above code. It appears that PHP (at least as of 5.1) uses a reference to whatever was returned by __get. To be more verbose, the above code is essentially identical to:

$tmp_array = &$myclass->foo;
$tmp_array['bar'] = 'baz';
unset(
$tmp_array);
?>

Therefore, the above won't do anything if your __get implementation resembles this:

function __get($name) {
    return
array_key_exists($name, $this->values)
        ?
$this->values[$name] : null;
}
?>

You will actually need to set the value in __get and return that, as in the following code:

function __get($name) {
    if (!
array_key_exists($name, $this->values))
       
$this->values[$name] = null;
    return
$this->values[$name];
}
?>

justmyoponion at gmail dot com

2 years ago

If you are not focused enough, then don't use it.
Otherwise it is very powerful and you can build very complex code that handle a lot of things like zend framework did.

PHP at jyopp dotKomm

16 years ago

Here's a useful class for logging function calls.  It stores a sequence of calls and arguments which can then be applied to objects later.  This can be used to script common sequences of operations, or to make "pluggable" operation sequences in header files that can be replayed on objects later.

If it is instantiated with an object to shadow, it behaves as a mediator and executes the calls on this object as they come in, passing back the values from the execution.

This is a very general implementation; it should be changed if error codes or exceptions need to be handled during the Replay process.
class MethodCallLog {
    private
$callLog = array();
    private
$object;

        public function

__construct($object = null) {
       
$this->object = $object;
    }
    public function
__call($m, $a) {
       
$this->callLog[] = array($m, $a);
        if (
$this->object) return call_user_func_array(array(&$this->object,$m),$a);
        return
true;
    }
    public function
Replay(&$object) {
        foreach (
$this->callLog as $c) {
           
call_user_func_array(array(&$object,$c[0]), $c[1]);
        }
    }
    public function
GetEntries() {
       
$rVal = array();
        foreach (
$this->callLog as $c) {
           
$rVal[] = "$c[0](".implode(', ', $c[1]).");";
        }
        return
$rVal;
    }
    public function
Clear() {
       
$this->callLog = array();
    }
}
$log = new MethodCallLog();
$log->Method1();
$log->Method2("Value");
$log->Method1($a, $b, $c);
// Execute these method calls on a set of objects...
foreach ($array as $o) $log->Replay($o);
?>

php at lanar dot com dot au

12 years ago

Note that __isset is not called on chained checks.
If isset( $x->a->b ) is executed where $x is a class with __isset() declared, __isset() is not called.

class demo
{
    var
$id ;
    function
__construct( $id = 'who knows' )
    {
       
$this->id = $id ;
    }
    function
__get( $prop )
    {
        echo
"\n", __FILE__, ':', __LINE__, ' ', __METHOD__, '(', $prop, ') instance ', $this->id ;
        return new
demo( 'autocreated' ) ; // return a class anyway for the demo
   
}
    function
__isset( $prop )
    {
        echo
"\n", __FILE__, ':', __LINE__, ' ', __METHOD__, '(', $prop, ') instance ', $this->id ;
        return
FALSE ;
    }
}
$x = new demo( 'demo' ) ;
echo
"\n", 'Calls __isset() on demo as expected when executing isset( $x->a )' ;
$ret = isset( $x->a ) ;
echo
"\n", 'Calls __get() on demo without call to __isset()  when executing isset( $x->a->b )' ;
$ret = isset( $x->a->b ) ;
?>

Outputs

Calls __isset() on demo as expected when executing isset( $x->a )
C:\htdocs\test.php:31 demo::__isset(a) instance demo
Calls __get() on demo without call to __isset()  when executing isset( $x->a->b )
C:\htdocs\test.php:26 demo::__get(a) instance demo
C:\htdocs\test.php:31 demo::__isset(b) instance autocreated

matthijs at yourmediafactory dot com

14 years ago

While PHP does not support true overloading natively, I have to disagree with those that state this can't be achieved trough __call.

Yes, it's not pretty but it is definately possible to overload a member based on the type of its argument. An example:
class A {

     public function

__call ($member, $arguments) {
    if(
is_object($arguments[0]))
     
$member = $member . 'Object';
    if(
is_array($arguments[0]))
     
$member = $member . 'Array';
   
$this -> $member($arguments);
  }

     private function

testArray () {
    echo
"Array.";
  }

     private function

testObject () {
    echo
"Object.";
  }
}

class

B {
}
$class = new A;
$class -> test(array()); // echo's 'Array.'
$class -> test(new B); // echo's 'Object.'
?>

Of course, the use of this is questionable (I have never needed it myself, but then again, I only have a very minimalistic C++ & JAVA background). However, using this general principle and optionally building forth on other suggestions a 'form' of overloading is definately possible, provided you have some strict naming conventions in your functions.

It would of course become a LOT easier once PHP'd let you declare the same member several times but with different arguments, since if you combine that with the reflection class 'real' overloading comes into the grasp of a good OO programmer. Lets keep our fingers crossed!

alexandre at nospam dot gaigalas dot net

15 years ago

PHP 5.2.1

Its possible to call magic methods with invalid names using variable method/property names:

class foo
{
    function
__get($n)
    {
       
print_r($n);
    }
    function
__call($m, $a)
    {
       
print_r($m);
    }
}
$test = new foo;
$varname = 'invalid,variable+name';
$test->$varname;
$test->$varname();?>

I just don't know if it is a bug or a feature :)

timshaw at mail dot NOSPAMusa dot com

14 years ago

The __get overload method will be called on a declared public member of an object if that member has been unset.

class c {
  public
$p ;
  public function
__get($name) { return "__get of $name" ; }
}
$c = new c ;
echo
$c->p, "\n" ;    // declared public member value is empty
$c->p = 5 ;
echo
$c->p, "\n" ;    // declared public member value is 5
unset($c->p) ;
echo
$c->p, "\n" ;    // after unset, value is "__get of p"
?>

Nanhe Kumar

8 years ago

//How can implement __call function you understand better
class Employee {

    protected

$_name;
    protected
$_email;
    protected
$_compony;

    public function

__call($name, $arguments) {
       
$action = substr($name, 0, 3);
        switch (
$action) {
            case
'get':
               
$property = '_' . strtolower(substr($name, 3));
                if(
property_exists($this,$property)){
                    return
$this->{$property};
                }else{
                   
$trace = debug_backtrace();
                   
trigger_error('Undefined property  ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
                    return
null;
                }
                break;
            case
'set':
               
$property = '_' . strtolower(substr($name, 3));
                if(
property_exists($this,$property)){
                   
$this->{$property} = $arguments[0];
                }else{
                   
$trace = debug_backtrace();
                   
trigger_error('Undefined property  ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
                    return
null;
                }

                                break;
            default :
                return

FALSE;
        }
    }

}

$s = new Employee();
$s->setName('Nanhe Kumar');
$s->setEmail('');
echo
$s->getName(); //Nanhe Kumar
echo $s->getEmail(); //
$s->setAge(10); //Notice: Undefined property setAge in
?>

Adeel Khan

15 years ago

Observe:

class Foo {
    function
__call($m, $a) {
        die(
$m);
    }
}
$foo = new Foo;
print
$foo->{'wow!'}();// outputs 'wow!'
?>

This method allows you to call functions with invalid characters.

daevid at daevid dot com

13 years ago

Here's a handy little routine to suggest properties you're trying to set that don't exist. For example:

Attempted to __get() non-existant property/variable 'operator_id' in class 'User'.

checking for operator and suggesting the following:

    * id_operator
    * operator_name
    * operator_code

enjoy.

    /**
     * Suggests alternative properties should a __get() or __set() fail
     *
     * @param     string $property
     * @return string
     * @author Daevid Vincent []
     * @date    05/12/09
     * @see        __get(), __set(), __call()
     */
   
public function suggest_alternative($property)
    {
       
$parts = explode('_',$property);
        foreach(
$parts as $i => $p) if ($p == '_' || $p == 'id') unset($parts[$i]);

        echo

'checking for '.implode(', ',$parts)." and suggesting the following:
\n";

        echo

"
    ";
            foreach(
    $this as $key => $value)
                foreach(
    $parts as $p)
                    if (
    stripos($key, $p) !== false) print '
  • '.$key."
  • \n"
    ;
            echo
    "
"
;
    }
just put it in your __get() or __set() like so:

    public function

__get($property)
    {
            echo
"

Attempted to __get() non-existant property/variable '".$property."' in class '".$this->get_class_name()."'.

\n";
           
$this->suggest_alternative($property);
            exit;
    }
?>

Daniel Smith

11 years ago

Be careful of __call in case you have a protected/private method. Doing this:

class TestMagicCallMethod {
    public function
foo()
    {
        echo
__METHOD__.PHP_EOL;
    }

    public function

__call($method, $args)
    {
        echo
__METHOD__.PHP_EOL;
        if(
method_exists($this, $method))
        {
           
$this->$method();
        }
    }

        protected function

bar()
    {
        echo
__METHOD__.PHP_EOL;
    }

    private function

baz()
    {
        echo
__METHOD__.PHP_EOL;
    }
}
$test    =    new TestMagicCallMethod();
$test->foo();
/**
* Outputs:
* TestMagicCallMethod::foo
*/
$test->bar();
/**
* Outputs:
* TestMagicCallMethod::__call
* TestMagicCallMethod::bar
*/
$test->baz();
/**
* Outputs:
* TestMagicCallMethod::__call
* TestMagicCallMethod::baz
*/
?>

..is probably not what you should be doing. Always make sure that the methods you call in __call are allowed as you probably dont want all the private/protected methods to be accessed by a typo or something.

dans at dansheps dot com

11 years ago

Since this was getting me for a little bit, I figure I better pipe in here...

For nested calls to private/protected variables(probably functions too) what it does is call a __get()  on the first object, and if you return the nested object, it then calls a __get() on the nested object because, well it is protected as well.

EG:
class A
{
protected
$B public function __construct()
{
$this->B = new B();
}

public function

__get($variable)
{
echo
"Class A::Variable " . $variable . "\n\r";
$retval = $this->{$variable};
return
$retval;
}
}

class

B
{
protected
$val public function __construct()
{
$this->val = 1;
}

public function

__get($variable)
{
echo
"Class B::Variable " . $variable . "\n\r";
$retval = $this->{$variable};
return
$retval;
}
}
$A = new A();

echo

"Final Value: " . $A->B->val;
?>

That will return something like...

Class A::Variable B
Class B::Variable val
Final Value: 1

It seperates the calls into $A->B and $B->val

Hope this helps someone

Marius

17 years ago

for anyone who's thinking about traversing some variable tree
by using __get() and __set(). i tried to do this and found one
problem: you can handle couple of __get() in a row by returning
an object which can handle consequential __get(), but you can't
handle __get() and __set() that way.
i.e. if you want to:
    print($obj->val1->val2->val3); // three __get() calls
?> - this will work,
but if you want to:
    $obj->val1->val2 = $val; // one __get() and one __set() call
?> - this will fail with message:
"Fatal error: Cannot access undefined property for object with
overloaded property access"
however if you don't mix __get() and __set() in one expression,
it will work:
    $obj->val1 = $val; // only one __set() call
   
$val2 = $obj->val1->val2; // two __get() calls
   
$val2->val3 = $val; // one __set() call
?>

as you can see you can split __get() and __set() parts of
expression into two expressions to make it work.

by the way, this seems like a bug to me, will have to report it.

strata_ranger at hotmail dot com

12 years ago

Combining two things noted previously:

1 - Unsetting an object member removes it from the object completely, subsequent uses of that member will be handled by magic methods.
2 - PHP will not recursively call one magic method from within itself (at least for the same $name).

This means that if an object member has been unset(), it IS possible to re-declare that object member (as public) by creating it within your object's __set() method, like this:

class Foo
{
  function
__set($name, $value)
  {
   
// Add a new (public) member to this object.
    // This works because __set() will not recursively call itself.
   
$this->$name= $value;
  }
}
$foo = new Foo();// $foo has zero members at this point
var_dump($foo);// __set() will be called here
$foo->bar = 'something'; // Calls __set()

// $foo now contains one member

var_dump($foo);// Won't call __set() because 'bar' is now declared
$foo->bar = 'other thing';?>

Also be mindful that if you want to break a reference involving an object member without triggering magic functionality, DO NOT unset() the object member directly.  Instead use =& to bind the object member to any convenient null variable.

php at sleep is the enemy dot co dot uk

15 years ago

Just to reinforce and elaborate on what DevilDude at darkmaker dot com said way down there on 22-Sep-2004 07:57.

The recursion detection feature can prove especially perilous when using __set. When PHP comes across a statement that would usually call __set but would lead to recursion, rather than firing off a warning or simply not executing the statement it will act as though there is no __set method defined at all. The default behaviour in this instance is to dynamically add the specified property to the object thus breaking the desired functionality of all further calls to __set or __get for that property.

Example:

class TestClass{

    public

$values = array();

        public function

__get($name){
        return
$this->values[$name];
    }

        public function

__set($name, $value){
       
$this->values[$name] = $value;
       
$this->validate($name);
    }

    public function

validate($name){
       
/*
        __get will be called on the following line
        but as soon as we attempt to call __set
        again PHP will refuse and simply add a
        property called $name to $this
        */
       
$this->$name = trim($this->$name);
    }
}
$tc = new TestClass();$tc->foo = 'bar';
$tc->values['foo'] = 'boing';

echo

'$tc->foo == ' . $tc->foo . '
'
;
echo
'$tc ' . (property_exists($tc, 'foo') ? 'now has' : 'still does not have') . ' a property called "foo"
'
;/*
OUPUTS:
$tc->foo == bar
$tc now has a property called "foo"
*/
?>

johannes dot kingma at gmail dot com

1 year ago

One interesting use of the __get function is property / function colaescence, using the same name for a property and a function.

Example:
class prop_fun {
    private
$prop = 123;

    public function

__get( $property ) {
        if(
property_exists( $this, $property ) ){
            return
$this-> $property;
        }
        throw new
Exception( "no such property $property." );
    }
    public function
prop() {
        return
456;
    }
}
$o = new prop_fun();

echo

$o-> prop . '
'
. PHP_EOL;
echo
$o-> prop() . '
'
. PHP_EOL;
?>

This will output 123 and 456. This does look like a funy cludge but I used it of a class containing a date type property and function allowing me to write

class date_class {
   
/** @property int $date */
   
private $the_date;

    public function

__get( $property ) {
        if(
property_exists( $this, $property ) ){
            return
$this-> $property;
        }
        throw new
Exception( "no such property $property." );
    }
    public function
the_date( $datetime ) {
        return
strtotime( $datetime, $this-> the_date );
    }

    public function

__construct()    {
       
$this-> the_date = time();
    }
}
$date_object = new date_class();$today = $date_object-> the_date;
$nextyear = $date_object-> the_date("+1 year");

echo

date( "d/m/Y", $today) . '
'
;
echo
date( "d/m/Y", $nextyear );
?>

Which I like because its self documenting properties. I used this in a utility class for user input.

turabgarip at gmail dot com

1 year ago

I concur that "overloading" is a wrong term for this functionality. But I disagree that this functionality is completely wrong. You can do "bad practice" with right code too.

For example __call() is very well applicable to external integration implementations which I am using to relay calls to SOAP methods which doesn't need local implementation. So you don't have to write "empty body" functions. Consider the SOAP service you connect has a "stock update" method. All you have to do is passing product code and stock count to SOAP.

class Inventory {

  public

__construct() {
   
// configure and connect to SOAP service
   
$this->soap = new SoapClient();
  }

  public

__call($soapMethod, $params) {
   
$this->soap->{$soapMethod}(params);
  }
}
// Now you can use any SOAP method without needing a wrapper
$stock = new Inventory();
$stock->updatePrice($product_id, 20);
$stock->saveProduct($product_info);?>

Of course you'd need a parameter mapping but it's in my honest opinion a lot better then having a plenty of mirror methods like:

class Inventory {

  public function

updateStock($product_id, $stock) {
   
$soapClient->updateStock($product_id, $stock;
  }
  public function
updatePrice($product_id, $price) {
   
$soapClient->updateStock($product_id, $price;
  }
 
// ...
}?>

DevilDude at darkmaker dot com

18 years ago

Php 5 has a simple recursion system that stops you from using overloading within an overloading function, this means you cannot get an overloaded variable within the __get method, or within any functions/methods called by the _get method, you can however call __get manualy within itself to do the same thing.

Is method overloading possible in PHP?

PHP does not support method overloading. In case you've never heard of method overloading, it means that the language can pick a method based on which parameters you're using to call it. This is possible in many other programming languages like Java, C++.

What is an example of method overloading?

In Java, two or more methods may have the same name if they differ in parameters (different number of parameters, different types of parameters, or both). These methods are called overloaded methods and this feature is called method overloading. For example: void func() { ... }

What is use of overloading in PHP?

Overloading in PHP provides means to dynamically create properties and methods. These dynamic entities are processed via magic methods one can establish in a class for various action types.