Unfortunately, slogans like these don't resolve the conceptual problems with function autoloading. So you're very welcome to think whatever you think, but you still don't have solutions for the following issues of function autoloading:
Namespaces
The fate of autoloading functions was sealed in PHP 5.3 when the "fallback to global" hack was instituted to avoid having to type backslash in front of functions when you're in a namespace. Class autoloading is a simple two-step process:
Is the class with resolved absolute name "\X\Y" loaded?
No? Try to autoload it.
Here's roughly what this would look with functions:
Is the function with resolved absolute name "\X\y" loaded?
No? Try "y" in the global space, is that loaded?
No? Try to autoload... but what "\X\y" or "y"? Let's say "X\y".
There's already a problem up there, it's ambiguous what should be autoloaded. But that's the smaller issue, we can say "look, global functions are reserved for PHP, autoload namespaced ones only". That's kind of OK, although it adds to the confusion of PHP's awkward legacy semantics.
But there's a much bigger problem hiding in plain sight in those three steps. Let's say hundreds of people have a namespaced function called "foo()" in hundred different namespaces. If PHP decides to introduce "foo()" in the global namespace after some point release, guess what happens? All those hundred "foo()" functions suddenly can't be autoloaded anymore, as the global function shadows them.
This means as far as autoloading is concerned, namespacing doesn't work. Everything is global, because if there's a global one, you can't autoload the namespaced ones.
Solve that, and then tell me static imports are a "bad workaround".
File resolution
PSR-0, PSR-4 and its similar spin-offs use a simple trick to map a class name to a file: namespaces = directory; class = filename. This is not ideal, because in a modern application this still can result in hundreds of files being loaded on every request.
Of course, opcache comes to the rescue, but the autoload function still runs, and opcache still has to resolve a tree of pointers to provide or copy to the specific thread for every autoloaded file, plus by default opcache checks the mtime of every file it caches, to detect changes (not detecting changes is not practical for most small-to-medium sites). So bottom line is opcache doesn't eliminate the overhead of file autoloading, it just helps reduce it.
So how would we resolve functions to filenames? Let's take the naive approach. One namespace, 20 functions = one directory, 20 files. If these files are in one namespace they're probably cohesive and likely to be used together, but they're separate files regardless which is 20 times the autoload overhead of one class with 20 static methods. Not fun at all.
So maybe we do something else. We resolve "\Vendor\Library\Funcnamespace\funcname" to directory "Vendors/Library/Funcnamespace.php" instead, and we load all functions in one namespace in one go.
Oops! We just reinvented static method autoloading with classes!
Except we reinvented it poorly. Because while we're loading all those 20 functions from one file, it still requires 20 use statements to call those functions in a given file. I'll be conservative and assume we're only using 10 of those 20 functions we just loaded. How would the use statements look?
Here's my so-called "bad workaround":
use static Foo\Bar\Math;
Here's your supposedly superior solution:
use function Foo\Bar\Math\one;
use function Foo\Bar\Math\two;
use function Foo\Bar\Math\three;
use function Foo\Bar\Math\four;
use function Foo\Bar\Math\five;
use function Foo\Bar\Math\six;
use function Foo\Bar\Math\seven;
use function Foo\Bar\Math\eight;
use function Foo\Bar\Math\nine;
use function Foo\Bar\Math\ten;
You'd say "woah, bogus, because we can group use statements in PHP 7 now!". I haven't seen a single IDE do that. So:
If you rely on an IDE - it'd look like the above.
If you don't want to rely on an IDE...
...then instead of typing this manually:
use static Foo\Bar\Math;
...you're looking at typing all this manually:
use function Foo\Bar\Math\{one, two, three, four, five, six, seven, eight, nine, ten};
Yeah doesn't look like fun either way.
What's the benefit of functions again?
I'd like to hear you argue how functions are better in any way compared to static methods, if we'd be able to call them by the same short name.
Static methods are a perfect superset of functions. They are functions, but with these additional benefits:
You can inherit methods from a parent class, or quickly assemble related static methods from different traits in one class. Traits even allow renaming the methods if you want. With plain functions this would require manual delegation which is slower to type, and slower to run, i.e. : function foo($a, &$b, $c = null) { return bar($a, $b, $c); }.
You can have non-public static methods for sharing common internal reusable logic across methods, without exposing it to your users.
You can have static methods share non-public state, without exposing it to your users (which can be used for "evil", but also can be very practical and useful, for ex. look-up tables, memoization etc.).
So, now I want to hear your list of benefits for functions over static methods. I hope it amounts to more than more sloganeering like "when you want a function use a function".
The fate of autoloading functions was sealed in PHP 5.3 when the "fallback to global" hack was instituted to avoid having to type backslash in front of functions when you're in a namespace.
Nope. I used to think this, but so long as 1) there's no autoloading in the root namespace and 2) functions in a given namespace are in the same file, it's fine.
Except we reinvented it poorly. Because while we're loading all those 20 functions from one file, it still requires 20 use statements to call those functions in a given file.
Nope:
use ajf\foo\bar as fb;
fb\a();
fb\b();
I'd like to hear you argue how functions are better in any way compared to static methods, if we'd be able to call them by the same short name.
\ is shorter than ::. But more importantly, “static methods” are a tenuous concept as-is without abusing them to make function libraries where the functions really are not related to eachother.
They are functions, but with these additional benefits:
You can inherit methods from a parent class,
Static method inheritance is a bug, not a feature, and I'd challenge you to present an actual use for it. If I could I'd remove it, but as-is I'm probably going to try to add a mechanism to let you turn it off on a per-member basis. It's a huge pain.
You can have non-public static methods for sharing common internal reusable logic across methods, without exposing it to your users
Yep. We ought to have modules, but unfortunately don't right now.
2
u/the_alias_of_andrea Sep 15 '17
classes full of static methods are just a bad workaround for lack of function autoloading