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

Reply via email to