Not autoloading functions

php.internals

Rasmus Schultz

9 years ago
Just a quick thought. Since the autoloading functions proposal is stalled, how about allowing for import of static functions instead? use function Foo::bar; bar(); // calls Foo::bar() There are two benefits to this approach: 1. There is immediate support for autoloading without any need for adoption or support in existing autoloaders. 2. Pseudo-namespaces (abstract classes with stateless static functions) are already widely practiced in PHP - a lot of existing code would be supported as is. The syntax when calling functions would be the same. If we had function autoloading, we would likely collect related functions in a file anyway - putting them in a class instead gives more less the same exact result. The only drawback I can see, is the inability to import a whole set of functions with one statement - but being explicit about external imports is widely considered best practice for classes and interfaces, so why not for functions. Yeah, it's a bit inconvenient, but at least we can move ahead and leverage existing code without changes or BC breaks. It's not all bad. It's better than nothing perhaps? :-) Thoughts?

Fleshgrinder

9 years ago
On 1/20/2017 8:04 AM, Rasmus Schultz wrote:
> Just a quick thought. > > Since the autoloading functions proposal is stalled, how about allowing for > import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar() > > There are two benefits to this approach: > > 1. There is immediate support for autoloading without any need for adoption > or support in existing autoloaders. > > 2. Pseudo-namespaces (abstract classes with stateless static functions) are > already widely practiced in PHP - a lot of existing code would be supported > as is. > > The syntax when calling functions would be the same. > > If we had function autoloading, we would likely collect related functions > in a file anyway - putting them in a class instead gives more less the same > exact result. > > The only drawback I can see, is the inability to import a whole set of > functions with one statement - but being explicit about external imports is > widely considered best practice for classes and interfaces, so why not for > functions. Yeah, it's a bit inconvenient, but at least we can move ahead > and leverage existing code without changes or BC breaks. It's not all bad. > It's better than nothing perhaps? :-) > > Thoughts? >
I actually like this idea a lot, something similar is possible in Rust with Enums. ```rust pub use self::Foo::{A, B}; pub enum Foo { A, B } fn main() { let a = A; } ``` Loading a set of static methods could look similar. ```php final class Foo { public static function A(): self { return new self; } public static function B(): self { return new self; } } ``` ```php use function Foo::{A, B}; $a = A(); ```
-- Richard "Fleshgrinder" Fussenegger

Paul M Jones

9 years ago
> On Jan 20, 2017, at 01:04, Rasmus Schultz <rasmus@mindplay.dk> wrote: > > Just a quick thought. > > Since the autoloading functions proposal is stalled, how about allowing for > import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar() >
...
> at least we can move ahead > and leverage existing code without changes or BC breaks. It's not all bad. > It's better than nothing perhaps? :-)
I find this intuitively appealing. It's an incremental change with tangible benefit in an imaginable timeframe, as vs a dramatic change in an unknowable timeframe. However, I am not an internals expert, so I'll leave it to them to say how big a deal it would be to implement, and what the drawbacks are.
-- Paul M. Jones pmjones88@gmail.com http://paul-m-jones.com Modernizing Legacy Applications in PHP https://leanpub.com/mlaphp Solving the N+1 Problem in PHP https://leanpub.com/sn1php

Stas Malyshev

9 years ago
Hi!
> Since the autoloading functions proposal is stalled, how about allowing for > import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar()
I'm not sure why it is good. This would certainly be confusing, if you call strlen and turns out it's completely different function from what you thought. One thing when it's the same namespace, at least you can be aware what this package does, but if it's just an arbitrary function from anywhere, it's really bad for understanding the code. How hard is it to write Foo::bar? You never have to go more than one level. I don't see a point in mixing internal function namespace with class methods for the sake of saving typing couple of characters.
-- Stas Malyshev smalyshev@gmail.com

Nikita Popov

9 years ago
On Fri, Jan 20, 2017 at 7:55 PM, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> Hi! > > > Since the autoloading functions proposal is stalled, how about allowing > for > > import of static functions instead? > > > > use function Foo::bar; > > > > bar(); // calls Foo::bar() > > I'm not sure why it is good. This would certainly be confusing, if you > call strlen and turns out it's completely different function from what > you thought. One thing when it's the same namespace, at least you can be > aware what this package does, but if it's just an arbitrary function > from anywhere, it's really bad for understanding the code. >
How is that different from the already existing "use function foo\bar\baz as strlen"?

Fleshgrinder

9 years ago
On 1/20/2017 7:58 PM, Nikita Popov wrote:
> On Fri, Jan 20, 2017 at 7:55 PM, Stanislav Malyshev <smalyshev@gmail.com> > wrote: > >> Hi! >> >>> Since the autoloading functions proposal is stalled, how about allowing >> for >>> import of static functions instead? >>> >>> use function Foo::bar; >>> >>> bar(); // calls Foo::bar() >> >> I'm not sure why it is good. This would certainly be confusing, if you >> call strlen and turns out it's completely different function from what >> you thought. One thing when it's the same namespace, at least you can be >> aware what this package does, but if it's just an arbitrary function >> from anywhere, it's really bad for understanding the code. >> > > How is that different from the already existing "use function foo\bar\baz > as strlen"? >
Or any other function that has no namespace separator in front. ``` <?php namespace Fleshgrinder\Examples; function strlen($string) { return 42; // Troll! =) } final class SomeClass { public function __construct() { echo strlen('f'); } } new SomeClass; ``` This is actually used by some in tests to provoke error conditions in built-in PHP functions to verify their error handling.
-- Richard "Fleshgrinder" Fussenegger

Rasmus Schultz

9 years ago
> How hard is it to write Foo::bar? You never have to go more
than one level. I don't see a point in mixing internal function namespace with class methods for the sake of saving typing couple of characters. I'm not suggesting we mix namespaces - this of course would be file-local, same as use-statements in general. You likely have to write a use-statement either way, if you're going to call a static function, e.g.: use Foo\Bar\HtmlHelper; echo HtmlHelper::escape($text); Versus: use Foo\Bar\HtmlHelper::escape; echo escape($text); It's not about "saving characters", that's not what use-statements are for - it's to avoid qualifying the same references repeatedly, which (for one) is better for source-control, whether that's a namespace or a class-name being repeated. Anyhow, it sounds like most of you are positive about this idea, so I will ponder the details and post a small RFC :-) On Jan 20, 2017 19:55, "Stanislav Malyshev" <smalyshev@gmail.com> wrote: Hi!
> Since the autoloading functions proposal is stalled, how about allowing
for
> import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar()
I'm not sure why it is good. This would certainly be confusing, if you call strlen and turns out it's completely different function from what you thought. One thing when it's the same namespace, at least you can be aware what this package does, but if it's just an arbitrary function from anywhere, it's really bad for understanding the code. How hard is it to write Foo::bar? You never have to go more than one level. I don't see a point in mixing internal function namespace with class methods for the sake of saving typing couple of characters.
-- Stas Malyshev smalyshev@gmail.com

Marcio Almada

9 years ago
Hi, Rasmus! 2017-01-21 4:14 GMT-04:00 Rasmus Schultz <rasmus@mindplay.dk>:
> > How hard is it to write Foo::bar? You never have to go more > than one level. I don't see a point in mixing internal function > namespace with class methods for the sake of saving typing couple of > characters. > > I'm not suggesting we mix namespaces - this of course would be file-local, > same as use-statements in general. > > You likely have to write a use-statement either way, if you're going to > call a static function, e.g.: > > use Foo\Bar\HtmlHelper; > echo HtmlHelper::escape($text); > > Versus: > > use Foo\Bar\HtmlHelper::escape; > echo escape($text); > > It's not about "saving characters", that's not what use-statements are for > - it's to avoid qualifying the same references repeatedly, which (for one) > is better for source-control, whether that's a namespace or a class-name > being repeated. > > Anyhow, it sounds like most of you are positive about this idea, so I will > ponder the details and post a small RFC :-) > > > On Jan 20, 2017 19:55, "Stanislav Malyshev" <smalyshev@gmail.com> wrote: > > Hi! > > > Since the autoloading functions proposal is stalled, how about allowing > for > > import of static functions instead? > > > > use function Foo::bar; > > > > bar(); // calls Foo::bar() > > I'm not sure why it is good. This would certainly be confusing, if you > call strlen and turns out it's completely different function from what > you thought. One thing when it's the same namespace, at least you can be > aware what this package does, but if it's just an arbitrary function > from anywhere, it's really bad for understanding the code. > > How hard is it to write Foo::bar? You never have to go more > than one level. I don't see a point in mixing internal function > namespace with class methods for the sake of saving typing couple of > characters. > > -- > Stas Malyshev > smalyshev@gmail.com >
I think this idea looks like the easiest way to avoid fixing the underlying problem. But it would irrevocably push functions to a "second class citizenship" of the language, in favor of static classes. It also would blurry the lines between namespaces and classes in a way we haven't seen before. Even though it feels pragmatic to do so, I'd prefer the harder path or at least wait for the next major until commit to this. Thanks, Márcio.

Andrew Faulds

9 years ago
Hi, Rasmus Schultz wrote:
> Since the autoloading functions proposal is stalled, how about allowing for > import of static functions instead?
The problem with stop-gap measures is they become entrenched, and the proper solution doesn't get implemented. But we may be at the risk of the latter anyway.
-- Andrea Faulds https://ajf.me/

Rasmus Schultz

9 years ago
> The problem with stop-gap measures is they become entrenched, and the
proper solution doesn't get implemented This would be my general point of view - unfortunately, functions are essentially useless at present, in a world with Composer, unless you're willing to preload all functions from all packages up-front. The only suggested solutions I've heard for the name resolution issue with function autoloading frankly are all horrible - much worse than this simple alternative. Add to that the fact that likely 90% of all functions in the wild (at least in Composer packages) are currently implemented as public static functions, and in my opinion, this is starting to sound less like a stop-gap and more like a simple solution to a problem we've been solving with a stop-gap for, oh, 10 years or so... On Jan 26, 2017 10:05 AM, "Andrea Faulds" <ajf@ajf.me> wrote:

Niklas Keller

9 years ago
> > > The problem with stop-gap measures is they become entrenched, and the > proper solution doesn't get implemented > > This would be my general point of view - unfortunately, functions are > essentially useless at present, in a world with Composer, unless you're > willing to preload all functions from all packages up-front. > > The only suggested solutions I've heard for the name resolution issue with > function autoloading frankly are all horrible - much worse than this simple > alternative. > > Add to that the fact that likely 90% of all functions in the wild (at least > in Composer packages) are currently implemented as public static functions, > and in my opinion, this is starting to sound less like a stop-gap and more > like a simple solution to a problem we've been solving with a stop-gap for, > oh, 10 years or so...
Again, if you choose to use static methods instead of functions, why do you need this special syntax for calling them then? Regards, Niklas

Rasmus Schultz

9 years ago
> if you choose to use static methods instead of functions
It's not a choice - functions are practically useless in a Composer context, and most everything PHP is now Composer packages.
> why do you need this special syntax for calling them then?
Yeah, but the same logic applies to namespaces and classes: If you choose to use namespaces, why do you need aliases for classes? Strictly speaking, you don't - but it would be really ugly and inconvenient. Forcing you to qualify a namespace or the parent class of a function repeatedly is just noise, same as qualifying the namespace before every class or interface-reference. Agreed, it has no functional value, but neither does namespace-aliasing. Both have a considerable organizational benefit though: the ability to list all your class, interface and function imports at the top of a file. To me, that's valuable. Either way, guys, here's a preliminary RFC: https://wiki.php.net/rfc/use-static-function While trying to describe this, I have to say, this doesn't appear to be the slam-dunk it seemed to be - you can read the details on that page, but given the two alternative approaches described on this page, it seems this feature is likely to create just as many problems and WTF as the auto-loading RFC. I'm afraid one isn't much better or worse than the other in that sense really... Oh well :-/ On Thu, Jan 26, 2017 at 6:50 PM, Niklas Keller <me@kelunik.com> wrote:

Walter Parker

9 years ago
On Thu, Jan 26, 2017 at 12:23 PM, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> > if you choose to use static methods instead of functions > > It's not a choice - functions are practically useless in a Composer > context, and most everything PHP is now Composer packages. > > Why are functions useless when using Composer? Is it because functions
can't be autoloaded? Is this about getting functions to load without having to stick them in classes that can be autoloaded?
> > why do you need this special syntax for calling them then? > > Yeah, but the same logic applies to namespaces and classes: > > If you choose to use namespaces, why do you need aliases for classes? > > Strictly speaking, you don't - but it would be really ugly and > inconvenient. Forcing you to qualify a namespace or the parent class of a > function repeatedly is just noise, same as qualifying the namespace before > every class or interface-reference. > > Agreed, it has no functional value, but neither does namespace-aliasing. > > Both have a considerable organizational benefit though: the ability to list > all your class, interface and function imports at the top of a file. > > To me, that's valuable. > > Either way, guys, here's a preliminary RFC: > > https://wiki.php.net/rfc/use-static-function > > While trying to describe this, I have to say, this doesn't appear to be the > slam-dunk it seemed to be - you can read the details on that page, but > given the two alternative approaches described on this page, it seems this > feature is likely to create just as many problems and WTF as the > auto-loading RFC. > > I'm afraid one isn't much better or worse than the other in that sense > really... > > Oh well :-/ > > > On Thu, Jan 26, 2017 at 6:50 PM, Niklas Keller <me@kelunik.com> wrote: > > > > The problem with stop-gap measures is they become entrenched, and the > >> proper solution doesn't get implemented > >> > >> This would be my general point of view - unfortunately, functions are > >> essentially useless at present, in a world with Composer, unless you're > >> willing to preload all functions from all packages up-front. > >> > >> The only suggested solutions I've heard for the name resolution issue > with > >> function autoloading frankly are all horrible - much worse than this > >> simple > >> alternative. > >> > >> Add to that the fact that likely 90% of all functions in the wild (at > >> least > >> in Composer packages) are currently implemented as public static > >> functions, > >> and in my opinion, this is starting to sound less like a stop-gap and > more > >> like a simple solution to a problem we've been solving with a stop-gap > >> for, > >> oh, 10 years or so... > > > > > > Again, if you choose to use static methods instead of functions, why do > > you need this special syntax for calling them then? > > > > Regards, Niklas > > >
-- The greatest dangers to liberty lurk in insidious encroachment by men of zeal, well-meaning but without understanding. -- Justice Louis D. Brandeis

Rowan Collins

9 years ago
On 26/01/2017 21:37, Walter Parker wrote:
> Why are functions useless when using Composer? Is it because functions > can't be autoloaded? > Is this about getting functions to load without having to stick them in > classes that can be autoloaded?
Yes, and yes. The subject line of this thread is an allusion to a conversation that resurfaces every now and then but always hits one roadblock or another. In short: the majority of PHP applications and frameworks are based around autoloading rather than long lists of explicit dependencies; functions can be inside a namespace; but such a function must be explicitly defined before use. Regards,
-- Rowan Collins [IMSoP]

Rowan Collins

9 years ago
On 26/01/2017 20:23, Rasmus Schultz wrote:
> Either way, guys, here's a preliminary RFC: > > https://wiki.php.net/rfc/use-static-function
Just to pick up on one thing you mention on there, declaring static classes. This has been discussed before, and an RFC went to a vote a couple of years ago and failed: https://wiki.php.net/rfc/abstract_final_class Part of the reasoning there was that people should be using namespaced functions instead - although that just leads us back to the autoloading debate... Regards,
-- Rowan Collins [IMSoP]

Niklas Keller

9 years ago
> > Since the autoloading functions proposal is stalled, how about allowing for > import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar() > > There are two benefits to this approach: > > 1. There is immediate support for autoloading without any need for adoption > or support in existing autoloaders. >
It adds "support". Just use a static method then instead of inventing some new alias system.
> 2. Pseudo-namespaces (abstract classes with stateless static functions) are > already widely practiced in PHP - a lot of existing code would be supported > as is. >
That same code is already supported, no need for a language change here.
> The syntax when calling functions would be the same. > > If we had function autoloading, we would likely collect related functions > in a file anyway - putting them in a class instead gives more less the same > exact result. > > The only drawback I can see, is the inability to import a whole set of > functions with one statement - but being explicit about external imports is > widely considered best practice for classes and interfaces, so why not for > functions.
Just import the class and you're fine, you have just imported a group of functions.
> Yeah, it's a bit inconvenient, but at least we can move ahead > and leverage existing code without changes or BC breaks. It's not all bad. > It's better than nothing perhaps? :-) > > Thoughts? >
I don't see any benefits here, just drawbacks. It adds yet another alias system, function calls can now be function calls and static methods. What's with the static scope? It gets lost here. Nothing shows there's a static scope. Strong -1 from me, sorry. Regards, Niklas

Nikita Popov

9 years ago
On Thu, Jan 26, 2017 at 10:46 AM, Niklas Keller <me@kelunik.com> wrote:
> > > > Since the autoloading functions proposal is stalled, how about allowing > for > > import of static functions instead? > > > > use function Foo::bar; > > > > bar(); // calls Foo::bar() > > > > There are two benefits to this approach: > > > > 1. There is immediate support for autoloading without any need for > adoption > > or support in existing autoloaders. > > > > It adds "support". Just use a static method then instead of inventing some > new alias system. > > > > 2. Pseudo-namespaces (abstract classes with stateless static functions) > are > > already widely practiced in PHP - a lot of existing code would be > supported > > as is. > > > > That same code is already supported, no need for a language change here. > > > > The syntax when calling functions would be the same. > > > > If we had function autoloading, we would likely collect related functions > > in a file anyway - putting them in a class instead gives more less the > same > > exact result. > > > > The only drawback I can see, is the inability to import a whole set of > > functions with one statement - but being explicit about external imports > is > > widely considered best practice for classes and interfaces, so why not > for > > functions. > > > Just import the class and you're fine, you have just imported a group of > functions. > > > > Yeah, it's a bit inconvenient, but at least we can move ahead > > and leverage existing code without changes or BC breaks. It's not all > bad. > > It's better than nothing perhaps? :-) > > > > Thoughts? > > > > I don't see any benefits here, just drawbacks. It adds yet another alias > system, function calls can now be function calls and static methods. What's > with the static scope? It gets lost here. Nothing shows there's a static > scope. >
A question in conjunction with this: How would this call actually treat the LSB and $this scope? Would it follow the normal rules for scoped method calls, or prevent adoption of scopes? For example: use A::__construct as ctor; class A { public function __construct() {} } class B extends A { public function __construct() { ctor(); } } Would this become an alternative way of writing parent::__construct() in B? Would it behave the same? Nikita

Nikita

9 years ago
On Fri, 20 Jan 2017 10:04:44 +0300, Rasmus Schultz <rasmus@mindplay.dk> wrote:
> Just a quick thought. > > Since the autoloading functions proposal is stalled, how about allowing > for > import of static functions instead? > > use function Foo::bar; > > bar(); // calls Foo::bar() > > There are two benefits to this approach: > > 1. There is immediate support for autoloading without any need for > adoption > or support in existing autoloaders. > > 2. Pseudo-namespaces (abstract classes with stateless static functions) > are > already widely practiced in PHP - a lot of existing code would be > supported > as is. > > The syntax when calling functions would be the same. > > If we had function autoloading, we would likely collect related functions > in a file anyway - putting them in a class instead gives more less the > same > exact result. > > The only drawback I can see, is the inability to import a whole set of > functions with one statement - but being explicit about external imports > is > widely considered best practice for classes and interfaces, so why not > for > functions. Yeah, it's a bit inconvenient, but at least we can move ahead > and leverage existing code without changes or BC breaks. It's not all > bad. > It's better than nothing perhaps? :-) > > Thoughts?
Maybe we might think about modules this time? Lots of languages use this approach and they seem to be pretty happy with it. Here's how it could look like, very abstractly. I don't really see any big issues with the way how to implement it either. https://gist.github.com/nikita2206/2e4ab1b314e840f93ed75a0b88266d35