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