Re: $this scoping (static methods) was: Bug 12622 Addressed in PHP 4.2.4?? Addressed in Zend 2.0??

From: Date: Sat, 14 Sep 2002 02:48:06 +0000
Subject: Re: $this scoping (static methods) was: Bug 12622 Addressed in PHP 4.2.4?? Addressed in Zend 2.0??
References: 1  Groups: php.dev 
Request: Send a blank email to php-dev+get-88314@lists.php.net to get a copy of this message
This pops up occasionally, Zeev/Andi should be able confirm that it's not currently in ZE2. As far as remedies go... the reason that currently $this is passed on all static method calls is to support parent:: and self::(ZE2), It has a few benefits- like making your code easier to read if you are using a long tree of inheritance: eg. where A extends b extends c extends d ... extends base_class { base_class::somemethod(); // inside A would at least enable you to work out what was being called. however, there are occasions where this is not desirable. (as a few bug reports have noted.) Solutions ----------------------- Suggested solution (for anybody wishing to implement it......) would be to declare static functions explicitly, and when calling these methods, no $this would be carried into the function scope. static function xxxxxx () { } Note: however there are alot of hidden implications to this, like dealing with inherited static methods? dealing with static and non static methods with the same name, extra compile time and exectute time checks/lookups.., more complex behavior making it 'easier to' accidentaly introduce user side bugs. Implementations? ---------------------- Option A) This could be implemented similarly to the private protected stuff: eg. name mangling on the function, a static function would be stored in the hash table as \0xxxxxx changes: Parser/compile time, an extra flex rule for this. (which adds the \0 on) (note: defining static function xxxx() and normal method xxxx() would be valid! -however the non static method would always be called = otherwise compile time checking would be required....) Execute time: when class::method() 's are called, first do a lookup on non-static method, then lookup on \0 prepended method. Cons: dealing with multiple definitions of a single method in a class would be slower at compile time (due to extra checks needed) -------------------- Option B) An additional flag on the function defintion (type zend_bool), that indicated if $this was to be passed on static methods. Cons: dealing with inheritance may prove odd/unexpected... - parent method x() is static. - inherited method x() is not... (programmers mistake for example)... how complex would the resolution method for this have to be... - compile time rules about not overriding static methods with non static methods...... --------------------- I guess the more you look at it, implementing this has alot of pitfalls - eg. moving from one 'not too bad' unexpected behavior ($this scoping), to a highly complex compile time checking that may induce interpretor or application errors accidentally..... thoughts/comments anybody... Regards Alan Shamim Islam wrote:
I have discovered this problem recently with my own work with classes and objects in PHP. It appears that something that is incorrect does not fail when it should. The original bug is listed at http://bugs.php.net/bug.php?id=12622 I discovered this in the process of posting my own bug report on this problem. PHP should catch these errors, IMHO as opposed to us spending time finding them. Also, is there anywhere in the documentation that correctly explains the semantics of when the $this context is passed to static method calls? I feel that to be in line with OO doctrines, any object should be able to call any method in its class hierarchy as if it were a class method call (including parent) (pass the $this) and any method not in its class hierarchy as a static method call (do not pass $this). This is illustrated below. Comments??? ========================================================== The following fails, but for the wrong reason. ========================================================== <?php error_reporting(E_ALL); class A { var $a; // Making a static call to class B - the only way it makes sense. function example(){echo $this->a;B::Example();} } class B extends A { var $b; // This should fail when called from objects of type A. // but not because b as a property is missing but because // $this is undefined in this context. function example(){echo $this->b;} } $a=new A; $a->example(); ?> ================================================================== The following DOES NOT fail, but it should. Causes a silent error ================================================================== <?php error_reporting(E_ALL); // Example of bug in PHP class method passing $this incorrectly class test1 { var $a; function test1() function showMe() { // Since test3::showMe was called as a static method // This too should be a static method call with no $this echo 'In test1::showMe<hr>'; echo 'Next 2 lines should fail since this method was not called from within this object<br>'; echo '$this is of type '. get_class($this)." in test3::showMe<br>\n"; echo "test1::showMe:a=".$this->a."<br>\n"; } // Class member to test static method call function callMe() { echo 'In test1::callMe<hr>'; echo '$this is of type '.get_class($this)."in test1::callMe<hr>\n"; echo 'Calling class method test3::showMe from an object of type test1<br>'; echo '$this should not be passed since test3::showMe does not exist in objects of type test1<hr>'; // This is a static method call, since test1 objects // do not have a test3::showMe. test3::showMe(); } } class test2 extends test1 { function showMe() { echo 'In test2::showMe<br>'; echo "Next 2 lines should fail since objects of type test1 cannot pass \$this<hr>\n"; echo '$this is of type '. get_class($this)." in test2::showMe<br>\n"; echo "test2::showMe:a=".$this->a."<hr>\n"; echo 'Calling parent::showMe<hr>'; // Since test3::showMe was called as a static method // This too should be a static method call with no $this parent::showMe(); } } class test3 extends test2 { function showMe() { echo 'In test3::showMe<br>'; echo "Next 2 lines should fail since objects of type test1 cannot pass \$this<hr>\n"; echo '$this is of type '. get_class($this)." in test3::showMe<br>\n"; echo "test3::showMe:a=".$this->a."<hr>\n"; echo 'Calling parent::showMe<hr>'; // Since test3::showMe was called as a static method // This too should be a static method call with no $this parent::showMe(); } } // object $a is of type test1 $a=new test1; $a->callMe(); ?>


« previous php.dev (#88314) next »