more static method fun

php.internals

Rob Richards

22 years ago
It is currently impossible to call a true static method from within a class method. It lets a class method call any object method statically even when not defined as a static method. The static method being called inherits the $this from the encapsulating object. This may not be a big deal with userspace objects, but it is impossible to handle for internal objects. Within the dom extension there are a few methods which can be called both statically and off an instantiated object. Calling them statically works fine until they are called within a class method as the function either expects this to be defined (meaning an instantiated object) or it to be null (when it is called statically). Since within the class method, it magically inherits the this of the object calling it, it currently crashes. The following is an example using simplexml to illustrate the problem (simplexml's code base is much smaller so easier to follow). Class AClass { function tester() { print simplexml_element::asXML(); // segfaults as this should not be allowed to be called statically } } $test = new AClass(); $test->tester(); And before someone says that the object type should be tested using zend_parse_method_parameters as a "workaround", it still wouldnt work correctly: Class BClass extends simplexml_element { function tester() { print simplexml_element::asXML(); } } $test = new BClass("<root/>"); $test->tester(); This doesnt crash, but because the static call is being called from within an object which extends simplexml_element, it would pass and act as if $this->asXML() was called, which also is incorrect. It should be issuing the same non-static method cannot be called statically error as when it is called outside a class. A better example of why it also would be incorrect would be using a domdocument: Class BClass extends domdocument { var $newdoc = NULL; function tester() { $this->newdoc = domdocument::loadXML("<root/>"); } } $test = new BClass(); $test->loadXML("<root>abc</root>"); print $test->saveXML()."\n"; $test->tester(); var_dump($test->newdoc); print $test->saveXML()."\n"; newdoc ends up as a boolean rather than a new document as $test is actually changed from the static call as it believes it is being called as $test's method and not as a static method, which should produce a new document rather than replacing the current document.

Greg Beaver

22 years ago
Hi, Rob Richards wrote:
> Within the dom extension there are a few methods which can be called both statically and off an instantiated object.
The PEAR base class also has this design flaw in several methods. It has caused nothing but annoying and unfixable bugs. The only good solution is to redesign by splitting the methods into two methods, one static, one not. It's best to do this before the stable label is applied, unless you like getting the same valid bugs reported over and over with different permutations :) Greg

Rob Richards

22 years ago
From: Greg Beaver
> The PEAR base class also has this design flaw in several methods. It > has caused nothing but annoying and unfixable bugs. The only good > solution is to redesign by splitting the methods into two methods, one > static, one not. It's best to do this before the stable label is > applied, unless you like getting the same valid bugs reported over and > over with different permutations :)
Say dom load were split into 2 methods (this is not something that should be required to do). One static and one a regular public function. As shown with the simplexml example, the regular function would still not work correctly. The method I used in that example, is not a static method, but if called within another class method, it is allowed to be called using the static syntax (which is not allowed when called that way outside of a class scope), and it also picks up the scope of the object that is is called from (which is wrong). To top it off, behavior of the statically called method is also affected by the type of the class calling it (also shown there). Rob

Greg Beaver

22 years ago
Hi Rob, Rob Richards wrote:
>From: Greg Beaver > > > >>The PEAR base class also has this design flaw in several methods. It >>has caused nothing but annoying and unfixable bugs. The only good >>solution is to redesign by splitting the methods into two methods, one >>static, one not. It's best to do this before the stable label is >>applied, unless you like getting the same valid bugs reported over and >>over with different permutations :) >> >> > >Say dom load were split into 2 methods (this is not something that should be >required to do). One static and one a regular public function. As shown with >the simplexml example, the regular function would still not work correctly. >The method I used in that example, is not a static method, but if called >within another class method, it is allowed to be called using the static >syntax >
To quote Microsoft, "this is a feature, not a bug." :) Of course, if someone tries to call a non-static method from another completely unrelated class, that's just stupid. But there are cases where you might want to call a method from a parent class 2 levels up. class one { function doSomething() {} } class two { function doSomething() {} } class three { function doSomething() { $a = one::doSomething(); } } Here, it's perfectly logical to allow :: as it is in fact not a static method call. If PHP removes this feature, it will break a lot of code I've written that has been working in a production environment for the past 2 years without a single glitch. I've also written code to emulate runtime multiple inheritance that relies upon using a method from another class that expects certain properties to be available in the class, and this works great. There is a certain amount of control that PHP can enforce, but in this case, I think it's up to the programmer's intelligence to understand how class hierarchies work, and not write code that fails. One point you raised that is significant to me is the crash, I don't think it's all that good that PHP 5 crashes instead of failing with some kind of fatal error. Greg

Rob Richards

22 years ago
> To quote Microsoft, "this is a feature, not a bug." :) Of course, if > someone tries to call a non-static method from another completely > unrelated class, that's just stupid. But there are cases where you > might want to call a method from a parent class 2 levels up.
I can see calling the method from a parent as valid, but from an unrelated class I see it as a bug. When calling a non-static method, it is allowed which it shouldnt be and when calling a method which can be either, it should be called as a true static method and not as a method of this unrelated object. The crashes can be fixed, but imo it should be fixed on the engine level rather than writing around the engine in the extensions as this behavior is just wrong. Rob

Andi Gutmans

22 years ago
Guys, This isn't going to change in the near future. Far too much code out there relies on this mis-feature :) Andi At 08:33 AM 3/3/2004 -0500, Greg Beaver wrote: