From bcf53732a1d7db68154f5b9ed0e553526d36dd15 Mon Sep 17 00:00:00 2001 From: Daniel Convissor Date: Thu, 20 Mar 2008 23:37:27 +0000 Subject: [PATCH] Clarify how overloading really works. [This is a work in progress. In middle of reviewing user comments and will post some questions to internals.] git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@255638 c90b9560-bf6c-de11-be94-00142212c4b1 --- language/oop5/overloading.xml | 364 ++++++++++++++++++---------------- 1 file changed, 193 insertions(+), 171 deletions(-) diff --git a/language/oop5/overloading.xml b/language/oop5/overloading.xml index 99b6615d70..606d0c3cee 100644 --- a/language/oop5/overloading.xml +++ b/language/oop5/overloading.xml @@ -1,27 +1,84 @@ - + Overloading - Both method calls and member accesses can be overloaded via the - __call, __get and __set methods. These methods will only be - triggered when your object or inherited object doesn't contain the - public member or method you're trying to access. - All overloading methods must be defined as - public. + Overloading in PHP provides means to dynamically + create members and methods. + These dynamic entities are processed via magic methods + one can establish in a class for various action types. + - Since PHP 5.1.0 it is also possible to overload the - isset and unset functions via the - __isset and __unset methods respectively. - Method __isset is called also with empty. + The overloading methods are invoked when interacting with + members 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 members and inaccessible + methods to refer to this combination of declaration + and visibility. + - PHP 5.3.0 added the ability to overload - static methods via __callStatic. + + All overloading methods must be defined as public. + + + None of the arguments of these magic methods can be + passed by + reference. + + + + + + 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. + + + + + + &reftitle.changelog; + + + + + + &Version; + &Description; + + + + + 5.1.0 + + Added __isset() and __unset(). + + + + 5.3.0 + + Added __callStatic(). + + + + + + + + + Member overloading @@ -44,119 +101,130 @@ - Class members can be overloaded to run custom code defined in your class - by defining these specially named methods. The $name - parameter used is the name of the variable that should be set or retrieved. - The __set() method's $value parameter specifies the - value that the object should set the $name. + __set() is run when writing data to + inaccessible members. - - - The __set() method cannot take arguments by reference. - - + + __get() is utilized for reading data from + inaccessible members. + + + + __isset() is triggered by calling + isset or empty + on inaccessible members. + + + + __unset() is invoked when + unset is used on inaccessible members. + + + + The $name argument is the name of the + member being interacted with. The __set() + method's $value argument specifies the + value the $name'ed member should be set + to. + + + + Member overloading only works in object context. These magic + methods will not be triggered in static context. Therefore + these methods can not be declared + static. + overloading with __get, __set, __isset and __unset example 1, "b" => 2, "c" => 3); +class MemberTest { + /** Location for overloaded data. */ + private $data = array(); - public function __get($nm) - { - echo "Getting [$nm]\n"; + /** Overloading not used on declared members. */ + public $declared = 1; - if (isset($this->x[$nm])) { - $r = $this->x[$nm]; - print "Returning: $r\n"; - return $r; - } else { - echo "Nothing!\n"; + /** Overloading not triggered when accessed inside 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: ' . $name . + ' in ' . $trace[0]['file'] . + ' on line ' . $trace[0]['line'], + E_USER_NOTICE); + $tmp = null; + return $tmp; } - public function __set($nm, $val) - { - echo "Setting [$nm] to $val\n"; - - if (isset($this->x[$nm])) { - $this->x[$nm] = $val; - echo "OK!\n"; - } else { - echo "Not OK!\n"; - } + public function __isset($name) { + echo "Is '$name' set?\n"; + return isset($this->data[$name]); } - public function __isset($nm) - { - echo "Checking if $nm is set\n"; - - return isset($this->x[$nm]); + public function __unset($name) { + echo "Unsetting '$name'\n"; + unset($this->data[$name]); } - public function __unset($nm) - { - echo "Unsetting $nm\n"; - - unset($this->x[$nm]); + /** Not a magic method, just here for example. */ + public function getHidden() { + echo "'hidden' visible here, __get() not used\n"; + return $this->hidden; } } -$foo = new Setter(); -$foo->n = 1; -$foo->a = 100; -$foo->a++; -$foo->z++; -var_dump(isset($foo->a)); //true -unset($foo->a); -var_dump(isset($foo->a)); //false +echo "
\n";
 
-// this doesn't pass through the __isset() method
-// because 'n' is a public property
-var_dump(isset($foo->n));
+$obj = new MemberTest;
 
-var_dump($foo);
+$obj->a = 1;
+echo $obj->a . "\n";
+
+var_dump(isset($obj->a));
+unset($obj->a);
+var_dump(isset($obj->a));
+
+echo $obj->declared . "\n";
+echo $obj->getHidden() . "\n";
+echo $obj->hidden . "\n";
 ?>
 ]]>
     
     &example.outputs;
     
 
-  int(1)
-  ["x":"Setter":private]=>
-  array(2) {
-    ["b"]=>
-    int(2)
-    ["c"]=>
-    int(3)
-  }
-}
+
+Notice:  Undefined property: hidden in  on line 64 in  on line 28
 ]]>
     
 
@@ -178,100 +246,54 @@ object(Setter)#1 (2) {
    
 
    
-    The magic methods __call() and __callStatic()
-    allow capturing invocation of non existent methods.
-    These methods can be used to implement user defined method
-    handling that depends on the name of the actual method being called. This
-    is for instance useful for proxy implementations. The arguments that were
-    passed in the function will be defined as an array in the
-    $arguments parameter. The value returned from these
-    methods will be returned to the caller of the method.
+    __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.
+   
 
    
-    overloading instantiated methods with __call
+    overloading instantiated methods with __call and ___callStatic
     
   x;
+    public function __call($name, $arguments) {
+        echo "Calling object method '$name' ";
+		echo implode(', ', $arguments). "\n";
+    }
+
+    public static function __callStatic($name, $arguments) {
+        echo "Calling static method '$name' ";
+		echo implode(', ', $arguments). "\n";
     }
 }
 
-$foo = new Caller();
-$a = $foo->test('a', 'b');
-var_dump($a);
+$obj = new MethodTest;
+$obj->test('in object context');
+
+MethodTest::test('in static context');
 ?>
 ]]>
     
     &example.outputs;
     
 
-  string(1) "a"
-  [1]=>
-  string(1) "b"
-}
-array(2) {
-  [0]=>
-  int(10)
-  [1]=>
-  int(20)
-}
-]]>
-    
-   
-
-   
-    overloading instantiated methods with __call
-    
-  
-]]>
-    
-    &example.outputs;
-    
-
-  string(1) "a"
-  [1]=>
-  string(1) "b"
-}
-array(2) {
-  [0]=>
-  int(10)
-  [1]=>
-  int(20)
-}
+Calling object method 'test' in object context
+Calling static method 'test' in static context
 ]]>