# Function auto-loading

- Thread: https://externals.io/message/94895
- Original archive: https://news-web.php.net/php.internals/94895
- Started by Rasmus Schultz on 2016-08-07T11:19:35+00:00
- Messages: 47
- RFC: Function Autoloading (Withdrawn) — https://externals.io/rfc/function_autoloading.md
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/94895.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #94895 — Rasmus Schultz — 2016-08-07T11:19:35+00:00

URL: https://externals.io/message/94895#94895

I'd really like to see the function auto-loading proposal revived and/or
possibly simplified.

The fact that functions are hard (in some cases impossible) to reach by
manually issuing require/include statements is, in my opinion, half the
difficulty, and a much more deeply rooted language problem exacerbating
what should be trivial problems - e.g. install a Composer package, import
(use) and call the functions.

Looks like a fair amount of work and discussion was done in 2013 on this
RFC:

https://wiki.php.net/rfc/function_autoloading

There was a (now stale) proof of concept implementation for the parent RFC
as well:

https://wiki.php.net/rfc/function_autoloading2

What happened?

It looks like the discussion stalled mostly over some concerns, including
reservations about performance, which were already disproved?

One issue apparently was left unaddressed, that of whether a call to an
undefined function should generate an auto-load call to a namespaced or
global function - I think this would not be difficult to address: trigger
auto-loading of the namespaced function first, check if it was loaded, and
if not, trigger auto-loading of the global function. Most likely a PSR
along with Composer auto-loading features will favor a best practice of
shipping packages with namespaced functions only, so the performance
implications of checking twice would be negligible in practice.

Being basically unable to ship or consume purely functional packages leaves
the functional side of the language largely an unused historical artifact,
which is sad. Keeping things functional and stateless often lead to more
predictable and obvious code - I think the absence of good support for
functions encourages a lot of over-engineering, e.g. developers
automatically making everything a class, not as a design choice, for the
sole reason of being able to ship and reuse what should be simple functions.

This RFC looks pretty solid to me.

What will it take to get this rolling again?

---

## #94896 — Fleshgrinder — 2016-08-07T11:22:22+00:00

URL: https://externals.io/message/94895#94896 · In reply to: #94895

> I'd really like to see the function auto-loading proposal revived and/or
> possibly simplified.
> 

+1 from my side for the revival. I would also love to see auto-loading
of namespaced constants like we have it for class constants.

-- 
Richard "Fleshgrinder" Fussenegger

---

## #94897 — Nikita Popov — 2016-08-07T11:29:39+00:00

URL: https://externals.io/message/94895#94897 · In reply to: #94895

> I'd really like to see the function auto-loading proposal revived and/or
> possibly simplified.
>
> The fact that functions are hard (in some cases impossible) to reach by
> manually issuing require/include statements is, in my opinion, half the
> difficulty, and a much more deeply rooted language problem exacerbating
> what should be trivial problems - e.g. install a Composer package, import
> (use) and call the functions.
>
> Looks like a fair amount of work and discussion was done in 2013 on this
> RFC:
>
> https://wiki.php.net/rfc/function_autoloading
>
> There was a (now stale) proof of concept implementation for the parent RFC
> as well:
>
> https://wiki.php.net/rfc/function_autoloading2
>
> What happened?
>
> It looks like the discussion stalled mostly over some concerns, including
> reservations about performance, which were already disproved?
>
> One issue apparently was left unaddressed, that of whether a call to an
> undefined function should generate an auto-load call to a namespaced or
> global function - I think this would not be difficult to address: trigger
> auto-loading of the namespaced function first, check if it was loaded, and
> if not, trigger auto-loading of the global function.


I feel like the problem here did not get across properly. Calling the
autoloader if a global function with the name exists will totally kill
performance. This means that every call to `strpos()` or any of the other
functions in the PHP standard library will have to go through the
autoloader first, unless people use fully qualified names (which,
currently, they don't). This is completely out of the question.

(The case where neither the namespaced nor the global function exists is
not the problem. In that case calling the autoloader for the namespaced and
non-namespaced names in sequence is of course unproblematic.)

Nikita


> Most likely a PSR
> along with Composer auto-loading features will favor a best practice of
> shipping packages with namespaced functions only, so the performance
> implications of checking twice would be negligible in practice.
>
> Being basically unable to ship or consume purely functional packages leaves
> the functional side of the language largely an unused historical artifact,
> which is sad. Keeping things functional and stateless often lead to more
> predictable and obvious code - I think the absence of good support for
> functions encourages a lot of over-engineering, e.g. developers
> automatically making everything a class, not as a design choice, for the
> sole reason of being able to ship and reuse what should be simple
> functions.
>
> This RFC looks pretty solid to me.
>
> What will it take to get this rolling again?

---

## #94898 — Rasmus Schultz — 2016-08-07T12:07:41+00:00

URL: https://externals.io/message/94895#94898 · In reply to: #94897

Of course calling e.g. `strpos()` should not trigger the auto-loader
repeatedly - can we cache the information that the auto-loader was
attempted once during the current script execution? so that e.g. only the
first call to `strpos()` triggers the auto-loader?

I suppose it would still happen once for every namespace from which
 `strpos()` gets called, so maybe this optimization doesn't help much.

I guess I'd say, benchmark it before making assumptions? Maybe the
performance hit turns out to be negligible in practice. Hard to say.

If a performance hit is inevitable, but marginal, I hope that we do not let
micro-benchmarks stand in the way of improving the language?

With PHP 7, the language is in many ways almost twice as fast as it was
before. I think it's fair to say, PHP has problems that are much bigger
than performance - to most developers, performance is not a pain point
anymore, if it was before PHP 7.

I wish that I could change your focus from performance concerns to actually
focusing on the language itself.

It seems that me that recent performance improvements have become somewhat
of a bottleneck that *prevents* new features and (worse) missing features
from completing and improving the language?

The performance improvements could just as well be viewed as a factor that
creates new elbow room for new features and language improvements, which,
long term, likely have much more value to more developers than the
performance of micro-benchmarks.

At the end of the day, for like 9 our of 10 projects, PHP's core
performance is not the bottleneck - things like database queries are. The
cost of developing a project is also generally unrelated to core
performance of the language. Hardware gets cheaper and faster every day. So
who or what are we optimizing for?

I don't mean to get too side-tracked from the original conversation here,
but we should be designing for developers - not for machines. The language
is more than fast enough for what most developers need it for - and still
nowhere near fast enough for, say, a JSON or XML parser, the kind of things
that require C or assembly level performance, and I really don't believe
there's a substantial segment of use-cases that fall in between - for most
things, either you need performance that PHP can't get near, or you need
language features and convenience that low-level languages can't deliver.

We're not competing with C - and if we're competing with other scripting
languages on performance, we're already in a pretty good position, and
people who select a scripting language aren't basing their choice on raw
performance in the first place; if that was their concern, they'd pick C.

We should focus on competing with other scripting languages on features,
convenience, productivity, etc. - if our main concern is competing on
low-level concerns like performance, those concerns will override the
points that really matter to developers who choose a high-level scripting
language, and we will lose.




> 
>
> > […]
>
>
> I feel like the problem here did not get across properly. Calling the
> autoloader if a global function with the name exists will totally kill
> performance. This means that every call to `strpos()` or any of the other
> functions in the PHP standard library will have to go through the
> autoloader first, unless people use fully qualified names (which,
> currently, they don't). This is completely out of the question.
>
> (The case where neither the namespaced nor the global function exists is
> not the problem. In that case calling the autoloader for the namespaced and
> non-namespaced names in sequence is of course unproblematic.)
>
> Nikita
>
>
> > […]

---

## #94903 — David Rodrigues — 2016-08-07T19:32:37+00:00

URL: https://externals.io/message/94895#94903 · In reply to: #94898

What should be the difference between a static method on a autoloaded class?

I guess that it could be done currently by use a static method.
In this case, I know exactly what method should be called, without
depends of an autoloader response.

class String {
    public static function strpos(...) { ... }
}

In this case, I just need to call String::strpos(...) and done.

I don't know if I'm missing something.

2016-08-07 9:07 GMT-03:00 Rasmus Schultz <rasmus@mindplay.dk>:
> Of course calling e.g. `strpos()` should not trigger the auto-loader
> repeatedly - can we cache the information that the auto-loader was
> attempted once during the current script execution? so that e.g. only the
> first call to `strpos()` triggers the auto-loader?
>
> I suppose it would still happen once for every namespace from which
> `strpos()` gets called, so maybe this optimization doesn't help much.
>
> I guess I'd say, benchmark it before making assumptions? Maybe the
> performance hit turns out to be negligible in practice. Hard to say.
>
> If a performance hit is inevitable, but marginal, I hope that we do not let
> micro-benchmarks stand in the way of improving the language?
>
> With PHP 7, the language is in many ways almost twice as fast as it was
> before. I think it's fair to say, PHP has problems that are much bigger
> than performance - to most developers, performance is not a pain point
> anymore, if it was before PHP 7.
>
> I wish that I could change your focus from performance concerns to actually
> focusing on the language itself.
>
> It seems that me that recent performance improvements have become somewhat
> of a bottleneck that *prevents* new features and (worse) missing features
> from completing and improving the language?
>
> The performance improvements could just as well be viewed as a factor that
> creates new elbow room for new features and language improvements, which,
> long term, likely have much more value to more developers than the
> performance of micro-benchmarks.
>
> At the end of the day, for like 9 our of 10 projects, PHP's core
> performance is not the bottleneck - things like database queries are. The
> cost of developing a project is also generally unrelated to core
> performance of the language. Hardware gets cheaper and faster every day. So
> who or what are we optimizing for?
>
> I don't mean to get too side-tracked from the original conversation here,
> but we should be designing for developers - not for machines. The language
> is more than fast enough for what most developers need it for - and still
> nowhere near fast enough for, say, a JSON or XML parser, the kind of things
> that require C or assembly level performance, and I really don't believe
> there's a substantial segment of use-cases that fall in between - for most
> things, either you need performance that PHP can't get near, or you need
> language features and convenience that low-level languages can't deliver.
>
> We're not competing with C - and if we're competing with other scripting
> languages on performance, we're already in a pretty good position, and
> people who select a scripting language aren't basing their choice on raw
> performance in the first place; if that was their concern, they'd pick C.
>
> We should focus on competing with other scripting languages on features,
> convenience, productivity, etc. - if our main concern is competing on
> low-level concerns like performance, those concerns will override the
> points that really matter to developers who choose a high-level scripting
> language, and we will lose.
>
>
> 
>
> > […]



-- 
David Rodrigues

---

## #94906 — Davey Shafik — 2016-08-07T22:42:16+00:00

URL: https://externals.io/message/94895#94906 · In reply to: #94903

On Sun, Aug 7, 2016 at 12:32 PM, David Rodrigues <david.proweb@gmail.com>
wrote:

> What should be the difference between a static method on a autoloaded
> class?
>
> I guess that it could be done currently by use a static method.
> In this case, I know exactly what method should be called, without
> depends of an autoloader response.
>
> class String {
>     public static function strpos(...) { ... }
> }
>
> In this case, I just need to call String::strpos(...) and done.
>
> I don't know if I'm missing something.
>
> 2016-08-07 9:07 GMT-03:00 Rasmus Schultz <rasmus@mindplay.dk>:
> > […]
> let
> > […]
> actually
> > […]
> somewhat
> > […]
> that
> > […]
> So
> > […]
> language
> > […]
> things
> > […]
> most
> > […]
> wrote:
> > […]
> wrote:
> > […]
> and/or
> > […]
> import
> > […]
> this
> > […]
> RFC
> > […]
> including
> > […]
> trigger
> > […]
> and
> > […]
> and
> > […]
> artifact,
> > […]
> more
> > […]
> the
> > […]
>

Perhaps the solution is to look at this as a forward-only feature, rather
than a backfill.

We only support autoloading for unambiguous names — if you want the
autoloader to be called, either
import the function with use, or use a [fully] qualified name.

This should remove the ambiguities and performance concerns.

- Davey

---

## #94914 — Rowan Collins — 2016-08-08T10:51:27+00:00

URL: https://externals.io/message/94895#94914 · In reply to: #94906

> Perhaps the solution is to look at this as a forward-only feature, rather
> than a backfill.
>
> We only support autoloading for unambiguous names — if you want the
> autoloader to be called, either
> import the function with use, or use a [fully] qualified name.
>
> This should remove the ambiguities and performance concerns.

I actually quite like this suggestion, because it fits with the use case 
I see as being most common: replacing static-only classes with a 
namespace of related functions. (Remember that "static classes" were 
rejected at RFC in favour of exactly this.)


To be clear, the case we'd be "refusing" to autoload (other than global 
functions themselves) would be a function in the *exact* current namespace:

namespace Acme\Foo\Bar;
do_something(); // won't autoload

But that only matters if namespace "\Acme\Foo\Bar" is split over 
multiple files. In this case, the declaration of 
"Acme\Foo\Bar\do_something()" would probably be in the same file anyway, 
so not need autoloading.


Given that we have hierarchical namespaces, this seems a more likely 
scenario:

namespace Acme\Foo\Bar;
// function autoload for 'Acme\Foo\Bar\Utilities\do_something'
Utilities\do_something();

Or importing as an alias:

namespace Acme\Foo\Bar;
use Acme\Stuff\Utilities as Util;
// function autoload for 'Acme\Stuff\Utilities\do_something'
Util\do_something();


Note that an unqualified function call "do_something()" already doesn't 
look in any imported namespaces, so "use Acme\Stuff\Utilities;" doesn't 
do anything to function name resolution.

So we would be defining a simple rule: "the function autoloader will be 
called at run time for any namespace-qualified function name which is 
not already defined".


This feels like a better compromise than an autoload cache, because I 
can see the invalidation rules getting messy, and heavily-used global 
functions still firing the autoloader for many different possible prefixes.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #94919 — Nikita Popov — 2016-08-08T12:15:25+00:00

URL: https://externals.io/message/94895#94919 · In reply to: #94914

On Mon, Aug 8, 2016 at 12:51 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
>
> > […]
>
> I actually quite like this suggestion, because it fits with the use case I
> see as being most common: replacing static-only classes with a namespace of
> related functions. (Remember that "static classes" were rejected at RFC in
> favour of exactly this.)
>
>
> To be clear, the case we'd be "refusing" to autoload (other than global
> functions themselves) would be a function in the *exact* current namespace:
>
> namespace Acme\Foo\Bar;
> do_something(); // won't autoload
>
> But that only matters if namespace "\Acme\Foo\Bar" is split over multiple
> files. In this case, the declaration of "Acme\Foo\Bar\do_something()" would
> probably be in the same file anyway, so not need autoloading.
>
>
> Given that we have hierarchical namespaces, this seems a more likely
> scenario:
>
> namespace Acme\Foo\Bar;
> // function autoload for 'Acme\Foo\Bar\Utilities\do_something'
> Utilities\do_something();
>
> Or importing as an alias:
>
> namespace Acme\Foo\Bar;
> use Acme\Stuff\Utilities as Util;
> // function autoload for 'Acme\Stuff\Utilities\do_something'
> Util\do_something();
>
>
> Note that an unqualified function call "do_something()" already doesn't
> look in any imported namespaces, so "use Acme\Stuff\Utilities;" doesn't do
> anything to function name resolution.
>
> So we would be defining a simple rule: "the function autoloader will be
> called at run time for any namespace-qualified function name which is not
> already defined".
>
>
> This feels like a better compromise than an autoload cache, because I can
> see the invalidation rules getting messy, and heavily-used global functions
> still firing the autoloader for many different possible prefixes.
>

I like this idea as well. In a previous thread I suggested to delay the
autoloader call for unqualified function calls until after the check for an
existing global function. But just not calling the autoloader at all for
unqualified calls is the better solution, as it removes one pretty
arbitrary factor (does this global function exist?) from the autoloader
behavior.

Nikita

---

## #94930 — Levi Morrison — 2016-08-08T14:36:25+00:00

URL: https://externals.io/message/94895#94930 · In reply to: #94897

>
>
> I feel like the problem here did not get across properly. Calling the
> autoloader if a global function with the name exists will totally kill
> performance. This means that every call to `strpos()` or any of the other
> functions in the PHP standard library will have to go through the
> autoloader first, unless people use fully qualified names (which,
> currently, they don't). This is completely out of the question.
>

Interesting. I come to a different conclusion: this a great opportunity to
get developers to use the fully qualified names. Performance is an
incredibly motivating force even in many situations when it shouldn't be.

---

## #94931 — Rowan Collins — 2016-08-08T14:56:11+00:00

URL: https://externals.io/message/94895#94931 · In reply to: #94930

> > […]
>
> Interesting. I come to a different conclusion: this a great opportunity to
> get developers to use the fully qualified names. Performance is an
> incredibly motivating force even in many situations when it shouldn't be.

An example just to focus the mind:

namespace Lovely\New\Code;

class Blah {
     function __construct(array $foo) {
          foreach ( $foo as $item ) {
               if ( strpos('blah', $item) !== 0 ) {
                   // ...
               }
          }
      }
}


This will *repeatedly* call the function autoloader for 
"Lovely\New\Code\strpos". The fully qualified name in this case is 
"\strpos".

I think saying "add a backslash in front of your function names to avoid 
them being slow" will just lead to lots of "lol wtf php sux".

If we wanted to make the \ mandatory, then the name resolution for 
functions could have had no fallback, just like class names. The reasons 
for having that fallback presumably still apply, so it doesn't make 
sense to now declare it "broken by design, please avoid".

On the other hand, saying "you can autoload functions from another 
namespace using qualified names or 'use function'" sidesteps the 
fallback issue, and sounds like a reasonable, non-BC-breaking, feature.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #94933 — michal@brzuchalski.com — 2016-08-08T15:15:51+00:00

URL: https://externals.io/message/94895#94933 · In reply to: #94931

IMHO if there were possibility to provide scalar objects like in Nikic
extension
https://nikic.github.io/2014/03/14/Methods-on-primitive-types-in-PHP.html
most of str* and many other functions could be called wythout FQN simply
from variable. Most of global scope functions interacting with scalars
could be called throught object handlers. In many legacy applications there
still could be possibility to call global functions. Most of legacy
applications have no namespace (Wordpress) so there is even no need for FQN
for function calls.

2016-08-08 16:56 GMT+02:00 Rowan Collins <rowan.collins@gmail.com>:

> 
>
> > […]
>
> An example just to focus the mind:
>
> namespace Lovely\New\Code;
>
> class Blah {
>     function __construct(array $foo) {
>          foreach ( $foo as $item ) {
>               if ( strpos('blah', $item) !== 0 ) {
>                   // ...
>               }
>          }
>      }
> }
>
>
> This will *repeatedly* call the function autoloader for
> "Lovely\New\Code\strpos". The fully qualified name in this case is
> "\strpos".
>
> I think saying "add a backslash in front of your function names to avoid
> them being slow" will just lead to lots of "lol wtf php sux".
>
> If we wanted to make the \ mandatory, then the name resolution for
> functions could have had no fallback, just like class names. The reasons
> for having that fallback presumably still apply, so it doesn't make sense
> to now declare it "broken by design, please avoid".
>
> On the other hand, saying "you can autoload functions from another
> namespace using qualified names or 'use function'" sidesteps the fallback
> issue, and sounds like a reasonable, non-BC-breaking, feature.
>
>
> Regards,
> --
> Rowan Collins
> [IMSoP]
>
> --
> 
> 
>
>


-- 
pozdrawiam
--
Michał Brzuchalski

---

## #94936 — Levi Morrison — 2016-08-08T16:00:24+00:00

URL: https://externals.io/message/94895#94936 · In reply to: #94931

>
> I think saying "add a backslash in front of your function names to avoid
> them being slow" will just lead to lots of "lol wtf php sux".
>

They'll say the same when function and class autoloading don't work the
same way anyway. I think unifying their behavior over time is the best
solution forward. Yes, I'm talking about a BC break eventually, but the
suggestion to autoload only fully qualified function names could buy us the
time to make that BC break less severe.

---

## #94937 — Niklas Keller — 2016-08-08T16:23:10+00:00

URL: https://externals.io/message/94895#94937 · In reply to: #94936

2016-08-08 18:00 GMT+02:00 Levi Morrison <levim@php.net>:

> > […]
>
> They'll say the same when function and class autoloading don't work the
> same way anyway. I think unifying their behavior over time is the best
> solution forward. Yes, I'm talking about a BC break eventually, but the
> suggestion to autoload only fully qualified function names could buy us the
> time to make that BC break less severe.
>

Loading only full qualified names will lead to strange bugs.

---

## #94939 — Rowan Collins — 2016-08-08T16:46:21+00:00

URL: https://externals.io/message/94895#94939 · In reply to: #94936

>     I think saying "add a backslash in front of your function names to
>     avoid them being slow" will just lead to lots of "lol wtf php sux".
>
>
> They'll say the same when function and class autoloading don't work the
> same way anyway. I think unifying their behavior over time is the best
> solution forward. Yes, I'm talking about a BC break eventually, but the
> suggestion to autoload only fully qualified function names could buy us
> the time to make that BC break less severe.


Do you mean eventually changing the name resolution rules for functions 
to match those for classes? I wasn't around at the time it was 
discussed, and if we were adding them now would be tempted to say the 
leading \ should always be mandatory, just like it is for classes. But 
since we have what we have, I don't see that big an advantage to 
changing it.

If not, I don't see why we ever need to be able to autoload global 
functions. "You want autoloading? Put it in a namespace." Like I say, 
that leaves the very small edge case of a single namespace spanning 
multiple files, and an autoloader implementation able to include one of 
them when a function is called from another.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #94940 — Rowan Collins — 2016-08-08T16:55:38+00:00

URL: https://externals.io/message/94895#94940 · In reply to: #94937

> Loading only full qualified names will lead to strange bugs.

The suggestion is to require *qualified* names (at least one \ in the 
call), not to require *fully qualified* names (leading \ and full 
namespace path). Function name resolution already requires that to 
reference anything other than a global function, or the exact current 
namespace.

The only scheme I can think of where it would matter is 
one-function-per-file, like Smarty's plugin loader.

# file foo.php
namespace Acme\Plugins;
function foo() { echo 'Hello world'; }

# file bar.php
namespace Acme\Plugins;
function bar() { foo(); } # will not autoload


Compared to "hundreds of lines of existing code will go slowly unless 
you liberally sprinkle with \", having to remind people not to do that 
seems like a small price to pay.


Regards,
-- 
Rowan Collins
[IMSoP]

---

## #94941 — Levi Morrison — 2016-08-08T17:03:27+00:00

URL: https://externals.io/message/94895#94941 · In reply to: #94939

>
> If not, I don't see why we ever need to be able to autoload global
> functions. "You want autoloading? Put it in a namespace." Like I say, that
> leaves the very small edge case of a single namespace spanning multiple
> files, and an autoloader implementation able to include one of them when a
> function is called from another.


I'm not sure why you would think a single namespace spanning multiple files
is a "very small edge case". I disagree. Here are some libraries I am aware
of *off the top of my head* that use functions the same namespace across
multiple files:

   - https://github.com/nikic/iter
   - https://github.com/lstrojny/functional-php

As well as several of my personal projects. I do not think this is a "very
small edge case."

---

## #94942 — Rasmus Schultz — 2016-08-08T17:06:33+00:00

URL: https://externals.io/message/94895#94942 · In reply to: #94939

> If not, I don't see why we ever need to be able to autoload global
functions

Well, for consistency.

For one, if you're refactoring a global function to a namespaced one, this
inconsistency is going to be surprising.

In general, any inconsistency in a language is surprising. Why only
non-global functions can autoload, is going to require a longer
explanation. And that's bad.

If we support auto-loading only for namespaced functions, we're actively
favoring (potentially micro-) performance over consistency.

I use global functions. I know that's not popular, but it's a language
feature, and I use it - for things like test-frameworks and global view
helper-functions.

Single namespace spanning multiple files is also a case for me - that's not
a decision we should make; likely, a PSR and Composer auto-loading features
will drive those decisions. One should have the freedom to add a new
function to an existing namespace, and make that function auto-load, while
packaging that function as a separate optionally-installable package.

I can't see the introduction of arbitrary restrictions or limitations
leading to anything good, language-wise.

Unless there's a demonstrated, critical performance issue with auto-loading
of global functions, please, let's not cripple this feature with
inconsistencies from the get-go!


On Mon, Aug 8, 2016 at 6:46 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
>
> > […]
>
>
> Do you mean eventually changing the name resolution rules for functions to
> match those for classes? I wasn't around at the time it was discussed, and
> if we were adding them now would be tempted to say the leading \ should
> always be mandatory, just like it is for classes. But since we have what we
> have, I don't see that big an advantage to changing it.
>
> If not, I don't see why we ever need to be able to autoload global
> functions. "You want autoloading? Put it in a namespace." Like I say, that
> leaves the very small edge case of a single namespace spanning multiple
> files, and an autoloader implementation able to include one of them when a
> function is called from another.
>
>
> Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #94946 — Rowan Collins — 2016-08-08T17:54:04+00:00

URL: https://externals.io/message/94895#94946 · In reply to: #94941

>     If not, I don't see why we ever need to be able to autoload global
>     functions. "You want autoloading? Put it in a namespace." Like I
>     say, that leaves the very small edge case of a single namespace
>     spanning multiple files, and an autoloader implementation able to
>     include one of them when a function is called from another.
>
>
> I'm not sure why you would think a single namespace spanning multiple
> files is a "very small edge case". I disagree. Here are some libraries I
> am aware of *off the top of my head* that use functions the same
> namespace across multiple files:
>
>   * https://github.com/nikic/iter
>   * https://github.com/lstrojny/functional-php
>
> As well as several of my personal projects. I do not think this is a
> "very small edge case."

The "iter" example looks a long way from being autoloadable whatever we 
supported, but the example of one-function-per-file is definitely 
relevant, so I stand corrected.

After a bit of clicking, I even managed to find a line which would fail 
to autoload under the proposed limitation:

https://github.com/lstrojny/functional-php/blob/master/src/Functional/CompareObjectHashOn.php

 > return compare_on($comparison, $keyFunction);

Although interestingly, at the top of the file there is a (technically 
unnecessary) "use function Functional\compose;" If there was a "use 
function Functional\compare_on;" as well, we'd be fine. (The function 
name would then become qualified at compile time and trigger autoloading 
at run time.)



 > Unless there's a demonstrated, critical performance issue with
 > auto-loading of global functions, please, let's not cripple this feature
 > with inconsistencies from the get-go!

Sure, we could try to measure it, but remember that it's not just the 
engine code that has the extra cost, it will actually call a userland 
function every time you use a global function from inside a namespace if 
you don't add a leading "\". That userland function will probably do a 
bunch of string comparisons before deciding it's not interested, and may 
even try to stat a file or two. Those are really expensive operations, 
so I think it's a long way from "micro-optimisation".

Unfortunately, function name resolution has this quirk that class name 
resolution doesn't, so something's got to give.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #94948 — Niklas Keller — 2016-08-08T19:04:32+00:00

URL: https://externals.io/message/94895#94948 · In reply to: #94942

2016-08-08 19:06 GMT+02:00 Rasmus Schultz <rasmus@mindplay.dk>:

> > […]
> functions
>
> Well, for consistency.
>

Not only for consistency, but also for things like polyfills, e.g.
random_compat.

Regards, Niklas


> For one, if you're refactoring a global function to a namespaced one, this
> inconsistency is going to be surprising.
>
> In general, any inconsistency in a language is surprising. Why only
> non-global functions can autoload, is going to require a longer
> explanation. And that's bad.
>
> If we support auto-loading only for namespaced functions, we're actively
> favoring (potentially micro-) performance over consistency.
>
> I use global functions. I know that's not popular, but it's a language
> feature, and I use it - for things like test-frameworks and global view
> helper-functions.
>
> Single namespace spanning multiple files is also a case for me - that's not
> a decision we should make; likely, a PSR and Composer auto-loading features
> will drive those decisions. One should have the freedom to add a new
> function to an existing namespace, and make that function auto-load, while
> packaging that function as a separate optionally-installable package.
>
> I can't see the introduction of arbitrary restrictions or limitations
> leading to anything good, language-wise.
>
> Unless there's a demonstrated, critical performance issue with auto-loading
> of global functions, please, let's not cripple this feature with
> inconsistencies from the get-go!
>
>
> On Mon, Aug 8, 2016 at 6:46 PM, Rowan Collins <rowan.collins@gmail.com>
> wrote:
>
> > […]
> to
> > […]
> and
> > […]
> we
> > […]
> that
> > […]
> a
> > […]

---

## #94949 — Rasmus Schultz — 2016-08-08T20:15:51+00:00

URL: https://externals.io/message/94895#94949 · In reply to: #94946

> Unfortunately, function name resolution has this quirk that class name
resolution doesn't, so something's got to give.

I suppose.

Well, then, how about making the feature work consistently for all
functions, by coupling it directly to the "use function" statement?

In other words, the feature changes from being strictly about auto-loading
functions, to instead resolving an imported function - so it would be
triggered by the "use function" statement only, rather than by the use of
the function, and the resolved function pertains only to the scope of the
file.

A function resolver would simply need to return a callable:

    register_function_resolver(function ($name) {
        if ($name === "html") {
            return function ($str) {
                return htmlspecialchars($str, ENT_HTML5);
            };
        }

        if (substr($name, 0, 5) === "iter\\") {
            require_once VENDOR_PATH."/nikic/iter/src/bootstrap.php";
            return $name;
        }
    });

This mechanism is probably a lot easier to explain and understand - and
works equally for global or namespaced functions.

It also lets you potentially do other weird shit, like overriding
 `var_dump()` or hooking into certain function calls - which could enable you
to do a bunch of evil, but I'm not really big on complicating features
solely to keep users from doing harm; simpler language features tend to
allow you to do more stuff - good or evil.

Likely the 99% use-case is simply for Composer to bootstrap your packages
for you, and this feature will permit you to do that.

Okay, so it doesn't deal with namespaced constants, and maybe this is me
being opinionated, but who's going to import constants one by one?
Constants are usually better off grouped together in a class. Although I
don't suppose there's any reason this concept couldn't be expanded to work
for constants as well, for completeness at least - though I have doubts
that very many people would care...

Anyways, just spitballing here :-)


On Mon, Aug 8, 2016 at 7:54 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
>
> > […]
>
> The "iter" example looks a long way from being autoloadable whatever we
> supported, but the example of one-function-per-file is definitely relevant,
> so I stand corrected.
>
> After a bit of clicking, I even managed to find a line which would fail to
> autoload under the proposed limitation:
>
> https://github.com/lstrojny/functional-php/blob/master/src/
> Functional/CompareObjectHashOn.php
>
> > […]
>
> Although interestingly, at the top of the file there is a (technically
> unnecessary) "use function Functional\compose;" If there was a "use
> function Functional\compare_on;" as well, we'd be fine. (The function name
> would then become qualified at compile time and trigger autoloading at run
> time.)
>
>
> 
> > […]
>
> Sure, we could try to measure it, but remember that it's not just the
> engine code that has the extra cost, it will actually call a userland
> function every time you use a global function from inside a namespace if
> you don't add a leading "\". That userland function will probably do a
> bunch of string comparisons before deciding it's not interested, and may
> even try to stat a file or two. Those are really expensive operations, so I
> think it's a long way from "micro-optimisation".
>
> Unfortunately, function name resolution has this quirk that class name
> resolution doesn't, so something's got to give.
>
>
> Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #94950 — Davey Shafik — 2016-08-08T20:23:26+00:00

URL: https://externals.io/message/94895#94950 · In reply to: #94949

> > […]
> resolution doesn't, so something's got to give.
>
> I suppose.
>
> Well, then, how about making the feature work consistently for all
> functions, by coupling it directly to the "use function" statement?
>
> In other words, the feature changes from being strictly about auto-loading
> functions, to instead resolving an imported function - so it would be
> triggered by the "use function" statement only, rather than by the use of
> the function, and the resolved function pertains only to the scope of the
> file.
>
> A function resolver would simply need to return a callable:
>
>     register_function_resolver(function ($name) {
>         if ($name === "html") {
>             return function ($str) {
>                 return htmlspecialchars($str, ENT_HTML5);
>             };
>         }
>
>         if (substr($name, 0, 5) === "iter\\") {
>             require_once VENDOR_PATH."/nikic/iter/src/bootstrap.php";
>             return $name;
>         }
>     });
>
> This mechanism is probably a lot easier to explain and understand - and
> works equally for global or namespaced functions.
>
> It also lets you potentially do other weird shit, like overriding
> `var_dump()` or hooking into certain function calls - which could enable you
> to do a bunch of evil, but I'm not really big on complicating features
> solely to keep users from doing harm; simpler language features tend to
> allow you to do more stuff - good or evil.
>
> Likely the 99% use-case is simply for Composer to bootstrap your packages
> for you, and this feature will permit you to do that.
>
> Okay, so it doesn't deal with namespaced constants, and maybe this is me
> being opinionated, but who's going to import constants one by one?
> Constants are usually better off grouped together in a class. Although I
> don't suppose there's any reason this concept couldn't be expanded to work
> for constants as well, for completeness at least - though I have doubts
> that very many people would care...
>
> Anyways, just spitballing here :-)
>
>
> On Mon, Aug 8, 2016 at 7:54 PM, Rowan Collins <rowan.collins@gmail.com>
> wrote:
>
> > […]
> relevant,
> > […]
> to
> > […]
> name
> > […]
> run
> > […]
> feature
> > […]
> so I
> > […]
>

Related to this, I'd like to see stream (and stream filter) autoloading.
Essentially, if you fopen("random://foo")  it'll pass that string to an
autoloader that will load and register the stream. It fails if at the end
of the autoloader the stream isn't registered.

Similar for filter and stream_filter_(pre|ap)pend() and loading stream
filters.

- Davey

---

## #94951 — Fleshgrinder — 2016-08-08T20:40:41+00:00

URL: https://externals.io/message/94895#94951 · In reply to: #94950

> 
> > […]

I mentioned auto-loading of constants because it would be nice to have
single consistent auto-loading mechanism in PHP for every importable
thing. This currently includes classes, interfaces, traits, functions,
and well constants.

The current composer approach of simply loading the file on every
request regardless of whether you need it ever or not works nicely too.


> Related to this, I'd like to see stream (and stream filter) autoloading.
> Essentially, if you fopen("random://foo")  it'll pass that string to an
> autoloader that will load and register the stream. It fails if at the end
> of the autoloader the stream isn't registered.
> 
> Similar for filter and stream_filter_(pre|ap)pend() and loading stream
> filters.
> 
> - Davey
> 

All resource related stuff is meant to die anyways from what I read and
was told in the past here and on GitHub so I guess this will not come.

-- 
Richard "Fleshgrinder" Fussenegger

---

## #94952 — Rasmus Schultz — 2016-08-08T20:44:29+00:00

URL: https://externals.io/message/94895#94952 · In reply to: #94950

Aren't stream wrappers already lazy-loaded?

e.g. stream_wrapper_register("random", RandomStreamWrapper::class) does not
afaik actually load anything.

Making stream wrappers directly registerable from e.g. "composer.json"
should be a near-trivial thing to implement, and would make them
effectively "autoload" - I imagine it's no more costly to pre-register the
protocol/class-name than e.g. pre-registering some other form of
auto-loader?




> 
>
> > […]
>
> Related to this, I'd like to see stream (and stream filter) autoloading.
> Essentially, if you fopen("random://foo")  it'll pass that string to an
> autoloader that will load and register the stream. It fails if at the end
> of the autoloader the stream isn't registered.
>
> Similar for filter and stream_filter_(pre|ap)pend() and loading stream
> filters.
>
> - Davey

---

## #94953 — Lester Caine — 2016-08-08T20:54:28+00:00

URL: https://externals.io/message/94895#94953 · In reply to: #94895

> Being basically unable to ship or consume purely functional packages leaves
> the functional side of the language largely an unused historical artifact,
> which is sad. Keeping things functional and stateless often lead to more
> predictable and obvious code - I think the absence of good support for
> functions encourages a lot of over-engineering, e.g. developers
> automatically making everything a class, not as a design choice, for the
> sole reason of being able to ship and reuse what should be simple functions.

I can understand a little the overwhelming desire to wrap everything in
it's own set of name spaces, but is that REALLY essential to make PHP
'work better'. What is wrong with a simple 'include_once' of the library
you want to use globally across all the code? I have a set of legacy
libraries who's function is not going to change any time soon which
works just the same on old setup's as it does on PHP7. And I see no
reason to even bother with namespace's ... they simply make a lot of
mess for no apparent gain! Where I could see a gain is if those
libraries were simply additional extensions pre-loaded into the engine
rather than something which needs 'auto-loading' at all.

-- 
Lester Caine - G8HFL
-----------------------------
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

---

## #94956 — Stanislav Malyshev — 2016-08-08T21:54:40+00:00

URL: https://externals.io/message/94895#94956 · In reply to: #94898

Hi!

> Of course calling e.g. `strpos()` should not trigger the auto-loader
> repeatedly - can we cache the information that the auto-loader was
> attempted once during the current script execution? so that e.g. only the
> first call to `strpos()` triggers the auto-loader?

I think triggering it even once for *every* internal function in the
code may be too much.

> I suppose it would still happen once for every namespace from which
> `strpos()` gets called, so maybe this optimization doesn't help much.

Exactly. Also, caching stuff assumes static environment. What if it
changes, e.g. autoloader gets different configuration?
-- 
Stas Malyshev
smalyshev@gmail.com

---

Next page: https://externals.io/message/94895.md?page=2
