protected __call() question

php.internals

Jochem Maas

22 years ago
the following code does not do what I expect, I made this test case after a new version of PHP5 was put on the system I am developing yesterday and some of my code no longer works: <? Class CallMe { public function setup() { $this->fakeMethod(); } protected function __call($method, $params) { echo 'you called CallMe::'.$method."\n"; } } echo <<< ___THEEND EXPECTED RESULT: ----------------------------------------- you called CallMe::fakeMethod ACTUAL RESULT: ----------------------------------------- ___THEEND; $obj = new CallMe(); $obj->setup(); ?> running the script on 'PHP 5.0.0RC2-dev (cli) (built: Apr 4 2004 13:07:13) (DEBUG)' gives me: <snip> EXPECTED RESULT: ----------------------------------------- you called CallMe::fakeMethod ACTUAL RESULT: ----------------------------------------- PHP Fatal error: Call to protected method CallMe::__call() from context '' in /var/www/santos/test/call.protected.php on line 7 Fatal error: Call to protected method CallMe::__call() from context '' in /var/www/santos/test/call.protected.php on line 7 </snip> Have I misunderstood the way PHP5 works? Or maybe something is broken? does anyone else get an error? I don't rule out that this could be something specific to the machine I am on, unfortunately I am limited by knowledge and access in determining if this is the case. Kind Regards, Jochem.

Marcus Börger

22 years ago
Hello Jochem, using 'protected' for __call() hides that mechanism from the outside world, hence the behavior is correct. Just drop protected and it should work as you expect. marcus Sunday, April 4, 2004, 9:49:44 PM, you wrote:
> the following code does not do what I expect, I made this test case > after a new version of PHP5 was put on the system I am developing > yesterday and some of my code no longer works:
> <?
> Class CallMe > { > public function setup() > { > $this->fakeMethod(); > }
> protected function __call($method, $params) > { > echo 'you called CallMe::'.$method."\n"; > } > }
> echo <<< ___THEEND > EXPECTED RESULT: > ----------------------------------------- > you called CallMe::fakeMethod
> ACTUAL RESULT: > -----------------------------------------
> ___THEEND;
> $obj = new CallMe(); > $obj->setup();
?>>

Derick Rethans

22 years ago
On Mon, 5 Apr 2004, Marcus Boerger wrote:
> Hello Jochem, > > using 'protected' for __call() hides that mechanism from the outside world, > hence the behavior is correct. Just drop protected and it should work as you > expect.
But it is not called from the outside world ... Derick

Ferdinand Beyer

22 years ago
On 5 Apr 2004 at 10:12, Derick Rethans wrote:
> But it is not called from the outside world ...
From the class' point of view: Yes, it is.
-- Ferdinand Beyer <fb@fbeyer.com>

Derick Rethans

22 years ago
On Mon, 5 Apr 2004, Ferdinand Beyer wrote:
> On 5 Apr 2004 at 10:12, Derick Rethans wrote: > > > But it is not called from the outside world ... > > From the class' point of view: Yes, it is.
It is called from a public function, how can that be outside of the class' point of view? Derick

Ferdinand Beyer

22 years ago
On 5 Apr 2004 at 11:23, Derick Rethans wrote:
> It is called from a public function, how can that be outside of the > class' point of view? > > Derick
Ah, now I understand your point. But __call() is called by the engine, not by setup(), so it is the outside world.... Class CallMe { public function setup() { $this->fakeMethod(); } protected function __call($method, $params) { echo 'you called CallMe::'.$method."\n"; } }
-- Ferdinand Beyer <fb@fbeyer.com>

Marcus Börger

22 years ago
Hello Ferdinand, that seems to be the current argument - but we have changed otehr places like that already so we should make this feature request or even bug. marcus Monday, April 5, 2004, 1:18:57 PM, you wrote:
> On 5 Apr 2004 at 11:23, Derick Rethans wrote:
>> It is called from a public function, how can that be outside of the >> class' point of view? >> >> Derick
> Ah, now I understand your point. But __call() is called by the engine, > not by setup(), so it is the outside world....
> Class CallMe > { > public function setup() > { > $this->fakeMethod(); > }
> protected function __call($method, $params) > { > echo 'you called CallMe::'.$method."\n"; > } > }
> -- > Ferdinand Beyer > <fb@fbeyer.com>
-- Best regards, Marcus mailto:helly@php.net

Jochem Maas

22 years ago
maybe its possible for the parser to ignore public/private/protected declarations on __call() (& also __set(), __get()) methods, given PHP forgiving nature/image (at least that is my impression). at the very least spare php-general a ton of emails by mentioning it prominently in the documentation.
-- conceptually speaking I'd don't think my PHP code should be concerned with 'the engine' in this regard, an undefined method was called this is handled by __call(), in the code the stack would go from CallMe::setup() to CallMe::__call() assuming PHP5 offers the such functionality for undefined methods, which is does. to me this seems, not broken, but incorrect in terms of behaviour. having said that I like PHP5 enough to just remove the 'protected' declaration and carry happily on as if nothing had happened! (my inner,perfectionist self will secretly keep hoping this is fixed so that I can make the __call() method on the particular object in question protected again, private even!) for what its worth +1 on making this a feature request. and keep up the good work! Marcus Boerger wrote: > Hello Ferdinand, > > that seems to be the current argument - but we have changed otehr places > like that already so we should make this feature request or even bug. > > marcus ... >>Ah, now I understand your point. But __call() is called by the engine, >>not by setup(), so it is the outside world.... > > >>Class CallMe >>{ >> public function setup() >> { >> $this->fakeMethod(); >> } > > >> protected function __call($method, $params) >> { >> echo 'you called CallMe::'.$method."\n"; >> } >>} > > ..

George Schlossnagle

22 years ago
On Apr 7, 2004, at 9:28 PM, Jochem Maas wrote:
> maybe its possible for the parser to ignore public/private/protected > declarations on __call() (& also __set(), __get()) methods, given PHP > forgiving nature/image (at least that is my impression).
The whole point of PPP is to not be forgiving or permissive unless you instruct the engine to do so. George

Jochem Maas

22 years ago
George Schlossnagle wrote:
> > On Apr 7, 2004, at 9:28 PM, Jochem Maas wrote: > >> maybe its possible for the parser to ignore public/private/protected >> declarations on __call() (& also __set(), __get()) methods, given PHP >> forgiving nature/image (at least that is my impression). > > > The whole point of PPP is to not be forgiving or permissive unless you > instruct the engine to do so.
which I don't want to (not sure right now what its set to.), and I agree with you, PPP is a very nice addition to PHP. I realise the suggestion was hacky but I was thinking more in terms of pre-empting a barrage of support emails I'm happy to just remove the P and add it again if ever that becomes an option. Thanks to everyone for your feedback. rgds, Jochem

Christian Schneider

22 years ago
Jochem Maas wrote:
> I'm happy to just remove the P and add it again if ever that becomes an > option.
Or go for the simpler option: Just don't use P. An addition to the documentation of __call saying that it has to be public makes sense though. The meaning of PPP on __call would be confusing anyway: Does it mean the implementation of __call or the visibility of the 'virtual' functions being called. I'd assume the first but people _will_ get confused. And I think __call has such few uses (I can think of one class right now: Object proxies for SOAP/ XMLRPC or the like) that you will hardly redeclare it anyway. If you start using __call on a regular basis you should probably rethink your design :-) - Chris

Marcus Börger

22 years ago
Hello Christian, Thursday, April 8, 2004, 8:09:20 AM, you wrote:
> Jochem Maas wrote: >> I'm happy to just remove the P and add it again if ever that becomes an >> option.
> Or go for the simpler option: Just don't use P.
> An addition to the documentation of __call saying that it has to be > public makes sense though. The meaning of PPP on __call would be > confusing anyway: Does it mean the implementation of __call or the > visibility of the 'virtual' functions being called. I'd assume the > first but people _will_ get confused.
Methos __call works as a proxy for the non existing/virtual methods hence i expect it's visibility makes the visibility of the virtual methods. If we want different visibility for the handled methods then we probably need a new keyword 'virtual' tha allows to declare a virtua methods visibility. Thats by the way also usefull for the virtual properties handled by __get/__set.
> And I think __call has such few uses (I can think of one class right > now: Object proxies for SOAP/ XMLRPC or the like) that you will hardly > redeclare it anyway. If you start using __call on a regular basis you > should probably rethink your design :-)
An iterator may want to "reflect" it's inner object/iterator methods by call. This you may cal aggregation. In other words you can use __call to emulate MI and aggregation.
-- Best regards, Marcus mailto:helly@php.net

Andi Gutmans

22 years ago
At 09:40 AM 4/8/2004 +0200, Marcus Boerger wrote:
> > And I think __call has such few uses (I can think of one class right > > now: Object proxies for SOAP/ XMLRPC or the like) that you will hardly > > redeclare it anyway. If you start using __call on a regular basis you > > should probably rethink your design :-) > >An iterator may want to "reflect" it's inner object/iterator methods >by call. This you may cal aggregation. In other words you can use >__call to emulate MI and aggregation.
Not only an iterator. I wrote a classic delegation (aggregation) example and it used __call(). Andi