On Sun, 17 Nov 2002, Stanislav Malyshev wrote: > BB>> related topic: in the current state of ze2, there are several ways to > BB>> call methods directly that can't be emulated by call_user_func() - > BB>> calling self::method() for instance, or the visibility of $this if > BB>> you call class::method(). is that likely to stay true? > > Since __call is the method of the class, calling self::method can be > achieved, I think. As for the second point - could you please explain > furher what you mean, maybe with an example?
right, because static method calls don't get caught by __call, so you always have $this. the basic problem is that as it is now, if i do any of these self::a_method($arg1,$arg2); parent::a_method($arg1,$arg2); some_other_class::a_method($arg1,$arg2); inside of a class's method, $this is visible inside those called methods, and points to the calling object. but there is no way to make equivalent calls using call_user_func() or call_user_func_array(). you can't use "parent::a_method", array($this,'parent::a_method'), array(parent,"a_method"), or array('parent',"a_method"). if you use the literal class name, call_user_func_array(array(get_parent_class($this),'a_method'), $args); it doesn't fail, but it's as if you were making a static method call from outside of an object context - $this is not defined. it's the last two cases - parent:: and some_other_class:: - that relate to __call(), as you point out. and what truly matters is call_user_func_array(), because not having it means you can't hand off the arguments from __call()'s parameters to a method in the parent class or in some other class. not without writing some pretty hacky eval() code, that is. (btw, there should probably be a warning in the docs that methods that are expecting to force their parameters to be references will not work as expected when called by call_user_func_array().) i'm attaching kind of long test case code & resulting output that show what i mean.
<?php class bar { var $z = 'initial value of z for bar'; function test($x=NULL,$y=NULL) { print "\tthis is bar::test x=".var_export($x,TRUE)." y=$y\n"; if (isset($this)) { print "\tbar::test - this->z = {$this->z}\n"; } else { print "\tbar::test - this is not set\n"; } } function __call($m,$a) {} } class base { var $z = 'initial value of z for base'; function test($x=NULL,$y=NULL) { print "\tthis is base::test x=".var_export($x,TRUE)." y=$y\n"; if (isset($this)) { print "\tbase::test - this->z = {$this->z}\n"; } else { print "\tbase::test - this is not set\n"; } self::whoami('self::whoami from base::test'); } function __call($m,$a) {} function whoami($caller=NULL) { print "\twhoami caller=$caller: __CLASS__ = ".__CLASS__."\n"; $class = get_class(new self); print "\twhoami caller=$caller: get_class(new self) = $class\n"; $class = get_class('self'); print "\twhoami caller=$caller: get_class('self') = $class\n"; if (isset($this)) { $class = get_class($this); } else { $class = '$this is not set'; } print "\twhoami caller=$caller: get_class(this) = $class\n"; } } class foo extends base { var $z = 'initial value of z for foo'; function test($x=NULL,$y=NULL) { print "\tthis is foo::test x=".var_export($x,TRUE)." y=$y\n"; if (isset($this)) { print "\tfoo::test - this->z = {$this->z}\n"; } else { print "\tfoo::test - this is not set\n"; } self::whoami('self::whoami from foo::test'); } function test_parent($x=NULL,$y=NULL) { ob_start(); $results = ''; $results .= "this is foo::test_parent x=".var_export($x,TRUE)." y=$y\n"; if (isset($this)) { $results .= "foo::test_parent - this->z = {$this->z}\n"; } else { $results .= "foo::test_parent - this is not set\n"; } $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] parent::test($x,$y);'."\n"; parent::test($x,$y); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array("parent::test",array($x,$y));'."\n"; call_user_func_array('parent::test',array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("parent","test"),array($x,$y));'."\n"; call_user_func_array(array('parent','test'),array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("base","test"),array($x,$y));'."\n"; call_user_func_array(array('base','test'),array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); ob_end_clean(); print "\n-------- begin test parent results ---------\n"; print $results; print "\n-------- end test parent results ---------\n"; } function test_self($x,$y) { $results = ''; ob_start(); $results .= "this is foo::test_self x=".var_export($x,TRUE)." y=$y\n"; if (isset($this)) { $results .= "foo::test_self - this->z = {$this->z}\n"; } else { $results .= "foo::test_self - this is not set\n"; } $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] self::test($x,$y)'."\n"; self::test($x,$y); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] foo::test($x,$y)'."\n"; foo::test($x,$y); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] bar::test($x,$y)'."\n"; bar::test($x,$y); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array("self::test",array($x,$y));'."\n"; call_user_func_array('self::test',array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("self","test"),array($x,$y));'."\n"; call_user_func_array(array('self','test'),array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("foo","test"),array($x,$y));'."\n"; call_user_func_array(array('foo','test'),array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("bar","test"),array($x,$y));'."\n"; call_user_func_array(array('bar','test'),array($x,$y)); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); ob_end_clean(); print "\n-------- begin test self results ---------\n"; print $results; print "\n-------- end test self results ---------\n"; } function __call($method,$args) { ob_start(); $results = ''; $results .= "this is foo::__call method=$method args=".var_export($args,TRUE)."\n"; $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call this->test($args)'."\n"; $this->test($args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call self::test($args)'."\n"; self::test($args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array($this,"test"),$args);'."\n"; call_user_func_array(array($this,'test'),$args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call parent::test($args)'."\n"; parent::test($args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array("parent::test",$args);'."\n"; call_user_func_array('parent::test',$args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array("parent","test"),$args);'."\n"; call_user_func_array(array('parent','test'),$args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); $parent = get_parent_class($this); $results .= "\n-----\n"; $results .= '$parent = get_parent($this); = '.$parent."\n"; $results .= "\n-----\n"; $results .= "\n-----\n"; $results .= __CLASS__.'::'.__FUNCTION__.'['.__LINE__.'] call_user_func_array(array($parent,"test"),$args);'."\n"; call_user_func_array(array($parent,'test'),$args); $results .= "\nbegin results:\n".ob_get_contents()."\nend results\n"; $results .= "\n-----\n"; @ob_clean(); ob_end_clean(); print "\n-------- begin test __call results ---------\n"; print $results; print "\n-------- end test __call results ---------\n"; } } print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of base::whoami('base::whoami',1);\n"; base::whoami('base::whoami',1); print "end output of base::test('base::whoami',1);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of foo::whoami('foo::whoami',1);\n"; foo::whoami('foo::whoami',1); print "end output of foo::whoami('foo::whoami',1);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of base::test('base::test',2);\n"; base::test('base::test',2); print "end output of base::test('base::test',2);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of foo::test('foo::test',2);\n"; foo::test('foo::test',2); print "end output of foo::test('foo::test',2);\n"; $x = new foo; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of x->test('x->test',3);\n"; $x->test('x->test',3); print "end output of x->test('x->test',3);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of x->nofunc('x->nofunc',3);\n"; $x->nofunc('x->nofunc',3); print "end output of x->nofunc('x->nofunc',3);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of x->test_parent('x->test_parent',3);\n"; $x->test_parent('x->test_parent',3); print "end output of x->test_parent('x->test_parent',3);\n"; print "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; print "begin output of x->test_self('x->test_self',3);\n"; $x->test_self('x->test_self',3); print "end output of x->test_self('x->test_self',3);\n"; ?>
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of base::whoami('base::whoami',1); whoami caller=base::whoami: __CLASS__ = base whoami caller=base::whoami: get_class(new self) = base whoami caller=base::whoami: get_class('self') = whoami caller=base::whoami: get_class(this) = $this is not set end output of base::test('base::whoami',1); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of foo::whoami('foo::whoami',1); whoami caller=foo::whoami: __CLASS__ = base whoami caller=foo::whoami: get_class(new self) = foo whoami caller=foo::whoami: get_class('self') = whoami caller=foo::whoami: get_class(this) = $this is not set end output of foo::whoami('foo::whoami',1); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of base::test('base::test',2); this is base::test x='base::test' y=2 base::test - this is not set whoami caller=self::whoami from base::test: __CLASS__ = base whoami caller=self::whoami from base::test: get_class(new self) = base whoami caller=self::whoami from base::test: get_class('self') = whoami caller=self::whoami from base::test: get_class(this) = $this is not set end output of base::test('base::test',2); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of foo::test('foo::test',2); this is foo::test x='foo::test' y=2 foo::test - this is not set whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = $this is not set end output of foo::test('foo::test',2); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of x->test('x->test',3); this is foo::test x='x->test' y=3 foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end output of x->test('x->test',3); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of x->nofunc('x->nofunc',3); -------- begin test __call results --------- this is foo::__call method=nofunc args=array ( 0 => 'x->nofunc', 1 => 3, ) ----- foo::__call[197] call this->test($args) begin results: this is foo::test x=array ( 0 => 'x->nofunc', 1 => 3, ) y= foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end results ----- ----- foo::__call[204] call self::test($args) begin results: this is foo::test x=array ( 0 => 'x->nofunc', 1 => 3, ) y= foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end results ----- ----- foo::__call[211] call_user_func_array(array($this,"test"),$args); begin results: this is foo::test x='x->nofunc' y=3 foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end results ----- ----- foo::__call[218] call parent::test($args) begin results: this is base::test x=array ( 0 => 'x->nofunc', 1 => 3, ) y= base::test - this->z = initial value of z for foo whoami caller=self::whoami from base::test: __CLASS__ = base whoami caller=self::whoami from base::test: get_class(new self) = base whoami caller=self::whoami from base::test: get_class('self') = whoami caller=self::whoami from base::test: get_class(this) = foo end results ----- ----- foo::__call[225] call_user_func_array("parent::test",$args); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'parent::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 226 end results ----- ----- foo::__call[232] call_user_func_array(array("parent","test"),$args); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'parent::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 233 end results ----- ----- $parent = get_parent($this); = base ----- ----- foo::__call[243] call_user_func_array(array($parent,"test"),$args); begin results: this is base::test x='x->nofunc' y=3 base::test - this is not set whoami caller=self::whoami from base::test: __CLASS__ = base whoami caller=self::whoami from base::test: get_class(new self) = base whoami caller=self::whoami from base::test: get_class('self') = whoami caller=self::whoami from base::test: get_class(this) = $this is not set end results ----- -------- end test __call results --------- end output of x->nofunc('x->nofunc',3); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of x->test_parent('x->test_parent',3); -------- begin test parent results --------- this is foo::test_parent x='x->test_parent' y=3 foo::test_parent - this->z = initial value of z for foo ----- foo::test_parent[86] parent::test($x,$y); begin results: this is base::test x='x->test_parent' y=3 base::test - this->z = initial value of z for foo whoami caller=self::whoami from base::test: __CLASS__ = base whoami caller=self::whoami from base::test: get_class(new self) = base whoami caller=self::whoami from base::test: get_class('self') = whoami caller=self::whoami from base::test: get_class(this) = foo end results ----- ----- foo::test_parent[93] call_user_func_array("parent::test",array($x,$y)); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'parent::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 94 end results ----- ----- foo::test_parent[100] call_user_func_array(array("parent","test"),array($x,$y)); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'parent::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 101 end results ----- ----- foo::test_parent[107] call_user_func_array(array("base","test"),array($x,$y)); begin results: this is base::test x='x->test_parent' y=3 base::test - this is not set whoami caller=self::whoami from base::test: __CLASS__ = base whoami caller=self::whoami from base::test: get_class(new self) = base whoami caller=self::whoami from base::test: get_class('self') = whoami caller=self::whoami from base::test: get_class(this) = $this is not set end results ----- -------- end test parent results --------- end output of x->test_parent('x->test_parent',3); -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= begin output of x->test_self('x->test_self',3); -------- begin test self results --------- this is foo::test_self x='x->test_self' y=3 foo::test_self - this->z = initial value of z for foo ----- foo::test_self[135] self::test($x,$y) begin results: this is foo::test x='x->test_self' y=3 foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end results ----- ----- foo::test_self[142] foo::test($x,$y) begin results: this is foo::test x='x->test_self' y=3 foo::test - this->z = initial value of z for foo whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = foo end results ----- ----- foo::test_self[149] bar::test($x,$y) begin results: this is bar::test x='x->test_self' y=3 bar::test - this->z = initial value of z for foo end results ----- ----- foo::test_self[156] call_user_func_array("self::test",array($x,$y)); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'self::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 157 end results ----- ----- foo::test_self[163] call_user_func_array(array("self","test"),array($x,$y)); begin results: Warning: call_user_func_array() [http://www.php.net/function.call-user-func-array]: First argumented is expected to be a valid callback, 'self::test' was given in /usr/local/book/apache/htdocs/book/ze2/call/test.php on line 164 end results ----- ----- foo::test_self[170] call_user_func_array(array("foo","test"),array($x,$y)); begin results: this is foo::test x='x->test_self' y=3 foo::test - this is not set whoami caller=self::whoami from foo::test: __CLASS__ = base whoami caller=self::whoami from foo::test: get_class(new self) = foo whoami caller=self::whoami from foo::test: get_class('self') = whoami caller=self::whoami from foo::test: get_class(this) = $this is not set end results ----- ----- foo::test_self[177] call_user_func_array(array("bar","test"),array($x,$y)); begin results: this is bar::test x='x->test_self' y=3 bar::test - this is not set end results ----- -------- end test self results --------- end output of x->test_self('x->test_self',3);
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, visit: http://www.php.net/unsub.php