Edit report at https://bugs.php.net/bug.php?id=40837&edit=1
ID: 40837 Comment by: ni...@php.net Reported by: nick dot telford at gmail dot com Summary: static and non-static functions can't have the same name Status: Not a bug Type: Bug Package: Class/Object related Operating System: Irrelevant PHP Version: 5.2.1 Block user comment: N Private report: N New Comment: @dmittner: > ":: is not a "static access operator", it's a "scope resolution operator". It > calls a method (or accesses a property) in a certain scope." > > Conceptually that one operator is trying to do too much. That "certain scope" > it's trying to use isn't chosen by the programmer; it's chosen by the > context; by where it's being used. That's presumptuous and an unnecessary > limitation. Maybe I didn't phrase that well enough. By "in a certain scope" I meant the class before the :: operator. In Foo::bar() the bar() method is called in the Foo scope. So, as you can see the scope *is* chosen by the programmer and no presumption takes place. > "::" is (AFAIK) the only way to access specifically static resources in one > context, but then is also used to reference the resources of special names in > other contexts. Again, this might be a misunderstanding. The scope-resolution behavior is *not* restricted to special names. It's not just about parent::foo() [and self::foo() and static::foo()], I just used that as an example as it is the most commonly used. You can do a scope-resolution call on any class in the inheritance hierarchy (e.g. a grandparent). Actually right now you could even do the call to using a scope that is outside the hierarchy, but thankfully we'll be removing that anti-feature in the next version. What we could obviously do - as you suggest - is strictly decouple scoped static method calls and scoped non-static method calls, by having a Foo::bar() syntax and a Foo->bar() syntax (e.g. parent->bar()). In my eyes that's a bad idea. We'd be adding a lot of new complexity (by making static methods *actually* different and not just a modifier of normal methods) only for the very small gain of having statics and non-statics of the same name. By the way, I just looked at a few other languages and it seems like nearly all went the same way as PHP. C++ doesn't allow it, C# doesn't allow it, Java doesn't allow it. Python doesn't really have statics, but it has the @staticmethod decorator and with that it's obviously not allowed either. The only language I looked at and which *does* support this is Ruby. So, I really don't see a solid case for this feature request. Previous Comments: ------------------------------------------------------------------------ [2013-04-21 21:47:20] billco at fnarg dot com My thoughts echo those of dmittner, while I think we all acknowledge the need for parent::method() functionality, I don't see why that small detail should invalidate this popular feature request. This seems like a limitation borrowed from C++, where it was a necessary evil of supporting multiple inheritance. PHP does not have MI and thus there was never a need for such a contrived "scope resolution" operator when something like Java's "super" would have sufficed. I can recognize that its usage dates back to the very beginning of PHP OOP, and it would be problematic to change the :: operator with all the existing code out there. Why can't we choose a new operator for pure static calls and get on with it ? It sounds like that would allow same-named static methods without ambiguity, while allowing the :: operator to continue as-is. ------------------------------------------------------------------------ [2013-04-21 18:57:01] dmittner at llnw dot com @ni...@php.net: While what you write is all technically correct, I think it comes down to this being the problem: ":: is not a "static access operator", it's a "scope resolution operator". It calls a method (or accesses a property) in a certain scope." Conceptually that one operator is trying to do too much. That "certain scope" it's trying to use isn't chosen by the programmer; it's chosen by the context; by where it's being used. That's presumptuous and an unnecessary limitation. "::" is (AFAIK) the only way to access specifically static resources in one context, but then is also used to reference the resources of special names in other contexts. Clearly people want to be able to call the same method name in both an object and static scope. It's the same reason people like function overloading: they have logic that accomplishes the same goal but done differently--this time based on scope. And we'd rather not dirty our code with resource names named differently just to identify scope. If the :: operator can't consistently serve this purpose because it's also having to accommodate "parent" and other special names, then maybe we just need a new operator specifically for calling methods in a static scope and ONLY for doing that. The more I think about this the more I think :: is just broken because it's treated inconsistently. There's probably good reasons I'm not thinking of, but it seems :: could have always meant "static scope" and "->" could have always meant "object scope"; and "parent->resource" would have been valid right alongside "parent::resource", each accessing the parent's resource in legitimately different scopes. So leave :: as it is for backwards compatibility. Add support for "->" on special names for object scope and a new operator specifically for static scope. Then we'll be able to define both object-scope and static-scope versions of the same resources and we'll have operators to access each consistently. Ultimately it's not a huge deal. It'd just be nice to be able to use the same names in both scopes. But we can at least achieve the functionality for now by naming everything "$staticVariable" and "staticMethod()". It's just really gross. ------------------------------------------------------------------------ [2013-04-21 09:40:32] ni...@php.net We *can not* have static and non-static methods with the same name. This is *not* just a backwards compatibility concern. I think the issue here is that you got the meaning of the :: operator wrong. :: is not a "static access operator", it's a "scope resolution operator". It calls a method (or accesses a property) in a certain scope. E.g. Foo::bar() calls the method bar() in the scope of class Foo. bar() here can be any method. A "static" method just means that the method does not need $this. The Foo::bar() call will only work if a) the method is static or b) the method is non-static and we have a $this. The distinction between "static access operator" and "scope resolution operator" is important and helps you understand why some things are as they are. For example, if you want to access a parent method, then what do you write? parent::foo(). This means that you call foo() in the parent scope. I get that people might argue whether "calling non-static methods with ::" is useful in the general case, but calling parent methods is something everybody should understand and find useful. And using that example it's also easy to see why you couldn't have the same static and non-static method. Consider this small example: class A { public function foo() { echo 'non-static'; } public static function foo() { echo 'static'; } } class B { public function bar() { echo parent::foo(); } } (new B)->bar(); // What do you get? Allowing static and non-static methods of the same name would require us to completely change the concept of scope-resolution and find a different way to call parent methods etc. So, just to say it again: Removing "::"-calls to non-static methods is *not* just a backwards compatibility issue, it would also cause problems with other, currently used and encouraged language features. Another thing that might help the understanding (apart from interpreting :: as scope-resolution) is not seeing static and non-static methods as distinct method types. Rather they are the same and "static" is just another method modifier like "public" or "final": You probably wouldn't ask to have "an abstract method and a final method of the same name", right? Asking for a non-static and static method of the same name makes similarly little sense. "static" just means "doesn't need $this" and nothing more. On a related note, this "static" modifier is also available for closures (i.e. you can write "$foo = static function() { ... }") and also means the same there, that the closure does not need $this. Prefixing a closure with "static" does not make it some kind of wholly different function type, it's just a modifier. Same for the static methods ;) I hope things are a bit clearer now. ------------------------------------------------------------------------ [2013-04-21 05:30:23] dmittner at llnw dot com I've got to add my vote to this feature. My use case consists of data validation methods. If called statically the validation tests are limited to things like string length, contents, etc. If called on an object it would include those tests (probably calling the static form of itself) and also comparative tests to other object conditions. I sympathize with backwards compatibility but sometimes you have to push forward. Case and point, some people I know are working with a Java-based system that doesn't support Java 7, so when building new servers they have to explicitly install an older version. Cutting a line between major PHP versions seems similarly viable. I'd also cite Magic Quotes which are completely removed in 5.4, which could similarly break older PHP4 compatibility. The precedent is set. Failing all that, how about a configuration option? ------------------------------------------------------------------------ [2012-11-20 02:13:10] capitaine dot gloumi at gmail dot com The "backward compatibility" should set to deprecated any static call of object method, and use it IF NO static method with the same name exist. I use static method and object method with same name in lot of paterns, it's useful in lot of case. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at https://bugs.php.net/bug.php?id=40837 -- Edit this bug report at https://bugs.php.net/bug.php?id=40837&edit=1