# [RFC] Function Autoloading (mark 5)

- Thread: https://externals.io/message/131332
- Original archive: https://news-web.php.net/php.internals/131332
- Started by Paul M.Jones on 2026-06-16T22:09:18+00:00
- Messages: 23
- RFC: Function Autoloading (mark 5) (Declined) — https://externals.io/rfc/function-autoloading-five-oh.md
- 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

---

## #131332 — Paul M.Jones — 2026-06-16T22:09:18+00:00

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

Hi all,

This is (by my count) a 5th attempt at adding function autoloading to PHP.

- RFC: https://wiki.php.net/rfc/function-autoloading-five-oh
- PR:  https://github.com/php/php-src/pull/22337

Looking forward to the discussion around this one!


-- pmj

---

## #131334 — Bob Weinand — 2026-06-16T22:22:46+00:00

URL: https://externals.io/message/131332#131334 · In reply to: #131332

Hey Paul,


> Hi all,
>
> This is (by my count) a 5th attempt at adding function autoloading to PHP.
>
> - RFC: https://wiki.php.net/rfc/function-autoloading-five-oh
> - PR:  https://github.com/php/php-src/pull/22337
>
> Looking forward to the discussion around this one!
>
>
> -- pmj


What is the motivation to not do a second call to the function 
autoloaders with "bar" (global namespace) when "bar()" is being called 
in the Foo namespace and the initial call with "Foo\bar" doesn't resolve 
to anything?

That would probably have much less rough edges, completely sidestepping 
the issue here with Foo\bar() not being found.


Thanks,
Bob

---

## #131335 — Rob Landers — 2026-06-16T22:55:48+00:00

URL: https://externals.io/message/131332#131335 · In reply to: #131332

> Hi all,
> 
> This is (by my count) a 5th attempt at adding function autoloading to PHP.
> 
> - RFC: https://wiki.php.net/rfc/function-autoloading-five-oh
> - PR:  https://github.com/php/php-src/pull/22337
> 
> Looking forward to the discussion around this one!
> 
> 
> -- pmj

I assume you saw my last attempt at this? :)

The general consensus was that spl autoloader needs to go and nobody wanted to see more added to it. That being said, maybe the list has changed its mind... hopefully.

— Rob

---

## #131342 — Anton Smirnov — 2026-06-17T10:03:07+00:00

URL: https://externals.io/message/131332#131342 · In reply to: #131332

> Hi all,
> 
> This is (by my count) a 5th attempt at adding function autoloading to PHP.
> 
> - RFC: https://wiki.php.net/rfc/function-autoloading-five-oh
> - PR:  https://github.com/php/php-src/pull/22337
> 
> Looking forward to the discussion around this one!
> 
> 
> -- pmj

Hi Paul!

> To make unqualified calls to `strlen()` resolve to Foo\strlen() inside the Foo namespace, you must import the fully qualified function first

Imagine we have an old guzzle/psr7 with stream_for function, and they 
use it without a qualifier. I defined a global stream_for so now I 
hijacked the internal library logic. Is it correct?

The previous attempt with namespace pinning made more sense to me

-- 
Anton

---

## #131350 — Rowan Tommins [IMSoP] — 2026-06-17T14:47:22+00:00

URL: https://externals.io/message/131332#131350 · In reply to: #131342

>Imagine we have an old guzzle/psr7 with stream_for function, and they use it without a qualifier. I defined a global stream_for so now I hijacked the internal library logic. Is it correct?
>
>The previous attempt with namespace pinning made more sense to me


The concern that occurred to me is similar: if I rely on function autoloading, but forget to fully-qualify a name in the current namespace, it would accidentally work as long as some other code triggered loading of that function first. Then some small refactoring - or even a different path through the code at runtime - and it will silently fall back to a function in the global namespace instead.

I think if autoloading is going to require some extra "ceremony" in the code, it would be preferable to have a declare() at the top of the file forcing the interpretation of all unqualified names (either "always assume current namespace" or "always assume global namespace"). That way, code would not change behaviour based on hard-to-predict side effects elsewhere. 



Rowan Tommins
[IMSoP]

---

## #131398 — Paul M. Jones — 2026-06-19T04:01:23+00:00

URL: https://externals.io/message/131332#131398 · In reply to: #131350

Hi all,

> 
> 
> 
> > […]
> 
> 
> The concern that occurred to me is similar: if I rely on function autoloading, but forget to fully-qualify a name in the current namespace, it would accidentally work as long as some other code triggered loading of that function first. Then some small refactoring - or even a different path through the code at runtime - and it will silently fall back to a function in the global namespace instead.
> 
> I think if autoloading is going to require some extra "ceremony" in the code, it would be preferable to have a declare() at the top of the file forcing the interpretation of all unqualified names (either "always assume current namespace" or "always assume global namespace"). That way, code would not change behaviour based on hard-to-predict side effects elsewhere.

Theodore Brown mentioned something like that as well in <https://externals.io/message/105757>.

Please see the following PR against my own branch to see what it would look like if added to the function-autoloading (mark 5) branch.

  https://github.com/pmjones/php-src/pull/1

Hypothetically this could be its own separate, precursor RFC and PR, but it's small enough it might go well here.

Thoughts?


-- pmj

---

## #131399 — Paul M. Jones — 2026-06-19T04:02:43+00:00

URL: https://externals.io/message/131332#131399 · In reply to: #131335

Hi Rob,

> 
> 
> I assume you saw my last attempt at this? :)

I did, I took notes!


> The general consensus was that spl autoloader needs to go and nobody wanted to see more added to it. That being said, maybe the list has changed its mind... hopefully.

One hopes.


-- pmj

---

## #131405 — Rowan Tommins [IMSoP] — 2026-06-19T11:31:19+00:00

URL: https://externals.io/message/131332#131405 · In reply to: #131398

>Please see the following PR against my own branch to see what it would look like if added to the function-autoloading (mark 5) branch.
>
>  https://github.com/pmjones/php-src/pull/1
>
>Hypothetically this could be its own separate, precursor RFC and PR, but it's small enough it might go well here.


Interesting that it's such a small change. My only comment would be that if we do add this, let's please not use the word "strict"; it tends to lead to incorrect assumptions like "strict is always better".

Some rather verbose names were suggested during the discussion of https://wiki.php.net/rfc/use_global_elements

My preference would be a 3-way switch, e.g. 

declare(function_const_ns='global');
declare(function_const_ns='current');
declare(function_const_ns='fallback');

I note that previous RFC was fairly comprehensively rejected, though, so you'd have to dig into why to figure out if it's worth resurrecting.


Rowan Tommins
[IMSoP]

---

## #131424 — Dan Ackroyd — 2026-06-20T12:18:54+00:00

URL: https://externals.io/message/131332#131424 · In reply to: #131332

Hi Paul,

> Looking forward to the discussion around this one!

I've very much in favour of autoloading.  Please can you address Bob's
concern:

Bob Weinand wrote:
> What is the motivation to not do a second call to the function
> autoloaders with "bar" (global namespace) when "bar()" is being called
> in the Foo namespace and the initial call with "Foo\bar" doesn't resolve
> to anything?
>
> That would probably have much less rough edges, completely sidestepping
> the issue here with Foo\bar() not being found.

I've also previously been involved in an RFC attempt for function
autoloading. I'm pretty certain that I came to the conclusion that for this
edge case; that the function autoloader needed to be called twice to have
the least surprising behaviour.

btw I don't think the RFC makes a strong case for why it is beneficial -
which keeps the RFC text short, but might leave people wondering why it is
needed. Some people don't see that function loading is useful (in exactly
the same way people didn't think class autoloading was useful) and so
aren't prepared to accept any trade-off. There is an overlapping problem of
people who are not maintainers pooh-poohing ideas just because they don't
personally want to use them.

It probably shouldn't be part of this RFC, but being able to bind closure
to functions, ala run runkit7-function-add^1 would taken function
autoloading from a medium useful thing, to a very powerful piece^2 of
technology.

Though as PIE https://github.com/php/pie exists (even though the PHP
extension ecosystem is "not a great experience") the argument for putting
even 'trivial' function into core might not be strong.

cheers
Dan
Ack


^1 the original runkit7_function_add is somewhat astonishing, with two
completely different function signatures in the same function. I've
stripped out to be a single function, without the operator overloading
here: https://github.com/Danack/fnbind/blob/main/fnbind.stub.php as an
extension.

^2 - I previously wrote some words on why function autoloading could be
powerful. Most of it still makes sense. If I had the energy, I'd add some
more words about 'making it easier to introduce complexity in a way that is
sanely hidden from users', which is good both for newbies learning to code,
and teams with a large codebases.

-------------------------


Okay, so to try to explain what I want to use it for and why....

* Auto-loading sometimes just isn't worth it
* Configurable per namespace functions are cool.
* Stuff I wouldn't personally condone using.

## Auto-loading sometimes just isn't worth it

So, this is something I've been thinking about since I gave some talks
about how awesome dependency is. In particular, one bit of the talk is
about the downsides of dependency injection.

[This slide](http://docs.basereality.com/InterfaceSegregationPortsmouth/#/42)
and the next one, show how easy 'bad' code is to use compared to
'dependency injected' code.

Although I told people in the talk that you get used to, I actually got
really annoyed at this overhead when I was actually writing tests for
'properly' written code.

Having to create and inject a logger class in every single test is just not
good value for money.

It kind of pains me to say it, but the Laravel way of using 'facades' aka
global functions hidden behind a static class is probably a better way of
doing things for certain types of object, particularly those where you are
only going to have one (or maybe a couple) of types of object in a given
environment.

For example, in a testing environment I would only use an in-memory logger,
and so I'd have some code like this:

```php
// Boring logger
interface Logger
{
    public function log(string $level, string $message);
}


// Logger used for tests.
class InMemoryDevLogger implements Logger
{
    private $log_entries = [];

    public function log(string $level, string $message) {
        $this->log_entries[] = [$level, $message];
        frwite(STDERR, $level . " : " . $message);
    }

    public function findMessage(string $pattern): array|null {
        foreach ($this->log_entries as $log_entry) {
            [$level, $message] = $log_entry;
            if (preg_match($pattern, $message) === 1) {
                return [$level, $message];
            }
        }

        return null;
    }
}

```

And then if you had some code that needed testing:

```php
// Currently, doing everything with dependency injection.

function do_the_needful(
    UserParams $user,
    UserRepo $userRepo,
    Logger $logger
) {
    $user = $userRepo->findUser($user->id);
    if ($user === null) {
        $logger->log("INFO", "User not found");
    }
    $logger->log("INFO", "User found, about to foo User");

    $result = fooUser($user);

    if ($result !== true) {
        $logger->log("INFO", "Failed to foo user.");
        return new ErrorResponse();
    }
    $logger->log("INFO", "User has been foo'd.");
    return new SuccessResponse();
}

```

You would write the test as:

```php

class SomeTest {

    function test_do_the_needful_UserNotFound()
    {
        $userParams = createFakeUserParams();
        $emptyRepo = new EmptyUserRepo();
        $logger = new InMemoryLogger();

        $result = do_the_needful(
            $userParams,
            $emptyRepo,
            $logger
        );

        $this->assertInstanceOf($result, ErrorResponse::class);
        $messageFound = $logger->findMessage(/* Some appropriate pattern
*/);
        $this->assertTrue($messageFound);
    }
}
```

This isn't the worst thing in the world....but it's just tedious.

## Why not just use Laravel style 'facades' ?

One of the really nice thing about using DI is that all of the config for
your application can be at the top-level of your app in a single place.
That much nicer than using a service locator where the creation of objects
can be all over the place.

It's also really nice to have a powerful enough config system to avoid
needing separate 'dev' config, and 'prod' config.

So, I'd really like to be able to setup a function autoloader like this:

```php

function bindLoggerFunctions()
{
    if (ENVIRONMENT == "DEV") {
        $logger = new InMemoryLogger();
        function_add('log', $logger->log(...));
        function_add('log_search', $logger->findMessage(...));
        return;
    }
    if (ENVIRONMENT == "PROD") {
        $logger = createMonologLogger();
        function_add('log', $logger->log(...));
        function_add('log_search', log_search_not_allowed(...));
    }
    throw \Exception("Unknown env: " . ENVIRONMENT);
}

function loader($name) {
    if ($name === 'log' || $name === 'log_search') {
        bindLoggerFunctions();
    }
}

```

Which would allow me to reduce my code to:


```php
function do_the_needful(
    UserParams $user,
    UserRepo $userRepo
) {
    $user = $userRepo->findUser($user->id);
    if ($user === null) {
        log("INFO", "User not found");
    }
    log("INFO", "User found, about to foo User");

    $result = fooUser($user);

    if ($result !== true) {
        log("INFO", "Failed to foo user.");
        return new ErrorResponse();
    }
    log("INFO", "User has been foo'd.");
    return new SuccessResponse();
}
```

And would reduce the test code to by a bit:
```php

class SomeTest {

    function test_do_the_needful_UserNotFound()
    {
        $userParams = createFakeUserParams();
        $emptyRepo = new EmptyUserRepo();

        $result = do_the_needful(
            $userParams,
            $emptyRepo
        );

        $this->assertInstanceOf($result, ErrorResponse::class);
        $messageFound = log_search(/* Some appropriate pattern */);
        $this->assertTrue($messageFound);
    }
}
```

It's not _the_ biggest thing in the world, and it's really easy for
code-purists to say "This isn't a big enough saving to be worth the
hackery" but anything that reduces the costs of writing tests is worth at
least some amount of tradeoff.


I think this pattern would only be worth using for any type of object that
never had any different implementations used in a test environment. So for
example, a UserRepo is going to have different implementations of things
like:

* EmptyUserRepo - for testing users not found
* SeededUserRepo - that contains prepared test accounts.
* ErrorUserRepo - all operations throw exceptions.

So that wouldn't be a good match for function binding....but for loggers,
there just doesn't seem to be any value in 'doing it properly'.


# Configurable per namespace functions are cool

Okay, so the second thing that would be possible (and is slightly
contradictory to the first one), is that


```php

namespace {

  funtion getLogClassNameForNamespace($namespace) {
        if ($namespace === 'Foo') {
            // For some reason, we care about Info log level stuff
            // in the Foo namespace.
            return InfoLogger::class;
        }

        // For everything else, we only care about warning.
        return WarningLogger::class;
  }

  function loader($name) {
    global $injector;

    $namespace_parts = explode('\\', $name);
    $function_name = array_pop($namespace_parts);
    $namespace = implode($namespace_parts);

    if ($function_name === 'log') {
        $loggerClassname = getLogClassNameForNamespace($namespace);
        $logger = $logger->make($loggerClassname);
        function_bind($name, $logger->log(...));
    }
  }

  autoload_register_function('loader');
}

namespace Foo {
    log('Info', "Hello there sailor!");
}

namespace Bar {
    log('Info', "Hello there sailor!");
}

```

* Stuff I wouldn't personally condone using

So I don't think I would ever code something like this:

```php

function add($x, $y) {
  return $x + $y;
}

function loader($name) {
  if (str_starts_with($name, "add_") === true) {
    $number = substr($name, strlen("add_"));
    $number = (int)$number;
    $fn = function ($x) use ($number) {
        return add($x, $y);
    }
    function_create("add_", $fn);
  }
}

autoload_register_function('loader');

$result = add_2(2);

```

But I have a suspicion people would be able to create some interesting
stuff.

---

## #131426 — tim@bastelstu.be — 2026-06-20T13:14:06+00:00

URL: https://externals.io/message/131332#131426 · In reply to: #131350

Hi

Am 2026-06-17 16:47, schrieb Rowan Tommins [IMSoP]:
> The concern that occurred to me is similar: if I rely on function 
> autoloading, but forget to fully-qualify a name in the current 
> namespace, it would accidentally work as long as some other code 
> triggered loading of that function first. Then some small refactoring - 
> or even a different path through the code at runtime - and it will 
> silently fall back to a function in the global namespace instead.

Agreed on this being a non-starter for the proposal for me.

Best regards
Tim Düsterhus

---

## #131427 — tim@bastelstu.be — 2026-06-20T13:19:15+00:00

URL: https://externals.io/message/131332#131427 · In reply to: #131405

Hi

Am 2026-06-19 13:31, schrieb Rowan Tommins [IMSoP]:
> Interesting that it's such a small change. My only comment would be 
> that if we do add this, let's please not use the word "strict"; it 
> tends to lead to incorrect assumptions like "strict is always better".

For reference, I did something similar a year ago in 
https://github.com/TimWolla/php-src/commit/aa6fc0c6ef3661e2fea4043ff1e07897952da2a5, 
with an additional variant of erroring when no explicit decision is 
made, which could also be a precusor to deprecate the global fallback 
entirely.

Best regards
Tim Düsterhus

---

## #131430 — Paul M. Jones — 2026-06-20T15:11:56+00:00

URL: https://externals.io/message/131332#131430 · In reply to: #131427

Hi Tim,

> 
> 
> Hi
> 
> Am 2026-06-17 16:47, schrieb Rowan Tommins [IMSoP]:
> 
> > […]
> 
> Agreed on this being a non-starter for the proposal for me.

I don't especially like it myself. FWIW, I don't actually *see* a lot of namespaced calls that this would fumble on (the vast majority of function autoloading I think would apply to global user functions based on my legacy work) but it's still kind of clunky.

As we know, it's caused by the namespace resolution rules, and I'd rather not take those on directly; the strict_namespace declaration might help to soothe it. Speaking of which:


> 
> 
> Hi
> 
> Am 2026-06-19 13:31, schrieb Rowan Tommins [IMSoP]:
> 
> > […]
> 
> For reference, I did something similar a year ago in https://github.com/TimWolla/php-src/commit/aa6fc0c6ef3661e2fea4043ff1e07897952da2a5, with an additional variant of erroring when no explicit decision is made, which could also be a precusor to deprecate the global fallback entirely.

Do you feel `force_global_function_fallback=false` and `strict_namespace=1` are substantially the same thing, or are they different in some way?



-- pmj

---

## #131508 — Paul M. Jones — 2026-06-23T20:55:41+00:00

URL: https://externals.io/message/131332#131508 · In reply to: #131334

Hi Bob,

(Sorry for the very long delay on this reply.)

> 
> 
> What is the motivation to not do a second call to the function autoloaders with "bar" (global namespace) when "bar()" is being called in the Foo namespace and the initial call with "Foo\bar" doesn't resolve to anything?

If I understand your question and the engine itself correctly:

The function autoloader only fires *after* the name resolution has occurred and no global fallback has been found. That final resolution of the name (the global one) is the only one that *can* be passed to the autoloader at that point. The original namespaced name just isn't available. That is: the resolver looks for the namespaced function, sees it is not defined, looks for a global name to fall back to, *that* one isn't defined, and then an error gets raised; the function autoloader kicks in at the moment the error would have been raised.

As far as I can tell, to get access to the original namespaced name, the implementation would have to hook into the name resolution logic, and that carries a more substantial set of troubles. Cf. these notes from years ago:

- S. Malyshev, 2013: https://externals.io/message/68693
- N. Popov, 2016: https://externals.io/message/94533 and https://externals.io/message/94897
- T. Brown, 2019: https://externals.io/message/105757

It looks like putting function autoloading the name resolution logic is huge a performance drag.


> That would probably have much less rough edges, completely sidestepping the issue here with Foo\bar() not being found.

There is the possibility of something like `declare(strict_namespace=1)` to avoid the global fallback entirely, which would give the autoloader the namespaced function name instead of the global one. (This is pretty much what Brown suggests above.) Do you feel that's a viable path forward?


-- pmj

---

## #131509 — Paul M. Jones — 2026-06-23T22:37:23+00:00

URL: https://externals.io/message/131332#131509 · In reply to: #131424

Hi Dan,

(Thanks for your patience while waiting on my reply.)


> 
> 
> I've very much in favour of autoloading.  Please can you address Bob's concern:

Replied, and (I hope) addressed -- I'm sure he will say if not.


> I've also previously been involved in an RFC attempt for function autoloading. I'm pretty certain that I came to the conclusion that for this edge case; that the function autoloader needed to be called twice to have the least surprising behaviour.

Does the suggestion of `declare(strict_namespace=1)` (suggested in various forms by others as well), to disable the global fallback on unqualified function and constant names, sound like a reasonable alternative?


> btw I don't think the RFC makes a strong case for why it is beneficial - which keeps the RFC text short, but might leave people wondering why it is needed. Some people don't see that function loading is useful (in exactly the same way people didn't think class autoloading was useful) and so aren't prepared to accept any trade-off. There is an overlapping problem of people who are not maintainers pooh-poohing ideas just because they don't personally want to use them.

Fair enough -- I did want to keep it short, but I can add some "motivation" narrative. I see your notes appended, I will incorporate them as I am able.

As long as we're here:

One of the early steps in the [MLAPHP][] process is to convert functions to static class methods. The idea is *not* to make the code "object- or class-oriented" but to make it "autoloadable." Doing so means you can get rid of include statements, thereby removing any side effects that might come includes. This makes the logical flow more comprehensible.

This conversion process is tedious and time consuming, even with artificial assistance. It would be much better if the functions could be autoloaded directly, and the include statements removed without having to do a conversion. The functions could be moved to an autoloadable location, leaving only side-effects (if any) in the included files. The whole refactoring process becomes much more tractable.

So in a way, a big motivation is "get rid of as many include statements as possible".


-- pmj


[MLAPHP]: https://leanpub.com/mlaphp

---

## #131797 — Paul M. Jones — 2026-07-07T16:45:25+00:00

URL: https://externals.io/message/131332#131797 · In reply to: #131332

Hi all,

I have updated the RFC and PR to add the `strict_namespace=1` directive as a way of solving for the global-fallback shadow-function case.

I have also added some research on how prevalent that case actually is; it turns out to be extremely rare among the top 1000 Packagist packages:

> In the end, it looks like there are only 2 packages and 8 call sites that would behave unexpectedly if they converted to function autoloading and dropped their include calls. Either a use function import or declare(strict_namespace=1) would fix each one.

I have not yet added the "motivation" section, as indicated by earlier comments, but still plan on doing so.

Please review again as convenient!


-- pmj

---

## #131798 — Michael Morris — 2026-07-07T16:56:47+00:00

URL: https://externals.io/message/131332#131798 · In reply to: #131797

> Hi all,
>
> I have updated the RFC and PR to add the `strict_namespace=1` directive as
> a way of solving for the global-fallback shadow-function case.
>
> I have also added some research on how prevalent that case actually is; it
> turns out to be extremely rare among the top 1000 Packagist packages:
>
> > […]
> that would behave unexpectedly if they converted to function autoloading
> and dropped their include calls. Either a use function import or
> declare(strict_namespace=1) would fix each one.
>
> I have not yet added the "motivation" section, as indicated by earlier
> comments, but still plan on doing so.
>
> Please review again as convenient!
>
>
> -- pmj
>

On another thread I've put in another way to accomplish this that is free
of the load order problems, can address constants as well and allows for
other actions related to namespace setup to be performed. "Improved
Autoloader" is the title.

---

## #131897 — tim@bastelstu.be — 2026-07-13T17:53:59+00:00

URL: https://externals.io/message/131332#131897 · In reply to: #131430

Hi

Apologies for getting back to you only now, the list is incredibly 
active and I needed to get back into the RFC and my old code.


> > […]
> 
> I don't especially like it myself. FWIW, I don't actually *see* a lot 
> of namespaced calls that this would fumble on (the vast majority of 
> function autoloading I think would apply to global user functions based 
> on my legacy work) but it's still kind of clunky.

Yes, (assumed) real-world use cases are not a good reason to add 
inconsistencies or gotchas into the language. Even 0.1% of code is a 
vast amount for PHP.

> > […]
> 
> Do you feel `force_global_function_fallback=false` and 
> `strict_namespace=1` are substantially the same thing, or are they 
> different in some way?

`force_global_function_fallback` in my implementation is just the 
existing known behavior. It's basically the *inverse* of 
`strict_namespace=1` from what I understand. It came out of a co-worker 
disliking both to fully-qualify global functions and to `use function` 
them. But at the same time, they are not using namespaced functions, so 
they wanted to *force* the use of the global functions to benefit from 
the compiler optimizations for some of the functions (e.g. 
`\sprintf()`). Personally I'm team “fully qualify everything”, so the 
`error_on_unqualified_function` part was my wishlist entry.

In any case, it isn't an RFC, so I have not given my implementation much 
consideration :-)

Best regards
Tim Düsterhus

---

## #131899 — tim@bastelstu.be — 2026-07-13T18:04:33+00:00

URL: https://externals.io/message/131332#131899 · In reply to: #131797

Hi


> I have updated the RFC and PR to add the `strict_namespace=1` directive 
> as a way of solving for the global-fallback shadow-function case.

I believe the `strict_namespace=1` directive is a sufficiently unrelated 
concern - with enormous bikeshedding potential on its own [1], but also 
sufficient usefulness on its own - such that I feel it should be its own 
RFC that is a prerequisite to this one. It should not be piggy-backed 
onto function autoloading.

In particular the autoloading gotcha will remain (no autoloading if a 
matching function exists), unless the user remembers to set the declare, 
which isn't much better than the original proposal.

Best regards
Tim Düsterhus

[1] e.g. do we want to bundle this with a deprecation

---

## #131905 — Paul M. Jones — 2026-07-13T20:08:45+00:00

URL: https://externals.io/message/131332#131905 · In reply to: #131899

Hi Tim,


> 
> 
> I believe the `strict_namespace=1` directive is a sufficiently unrelated concern - with enormous bikeshedding potential on its own [1], but also sufficient usefulness on its own - such that I feel it should be its own RFC that is a prerequisite to this one. It should not be piggy-backed onto function autoloading.

I'm good with that. I'll prepare a separate RFC and remove that from the function-autoloading one.


> In particular the autoloading gotcha will remain (no autoloading if a matching function exists), unless the user remembers to set the declare, which isn't much better than the original proposal.

In fairness, that particular gotcha looks to be very rare among the top 1000 packages -- the principle remains, but in practice it appears almost nonexistent.


-- pmj

---

## #131930 — Paul M. Jones — 2026-07-15T00:57:58+00:00

URL: https://externals.io/message/131332#131930 · In reply to: #131905

> 
> 
> Hi Tim,
> 
> 
> > […]
> 
> I'm good with that. I'll prepare a separate RFC and remove that from the function-autoloading one.

Done: https://wiki.php.net/rfc/strict-namespace

I will update the function autoloading RFC as needed to refer back to strict-namespace instead of incorporating it.


-- pmj

---

## #131945 — Paul M. Jones — 2026-07-15T18:35:25+00:00

URL: https://externals.io/message/131332#131945 · In reply to: #131930

Hi all,

> 
> 
> 
> 
> > […]
> 
> Done: https://wiki.php.net/rfc/strict-namespace
> 
> I will update the function autoloading RFC as needed to refer back to strict-namespace instead of incorporating it.

The RFC has been updated to un-incorporate the strict-namespace elements; if there are no further substantive comments, I would like to open the vote in 2-ish weeks.


-- pmj

---

## #132155 — tim@bastelstu.be — 2026-07-31T17:12:01+00:00

URL: https://externals.io/message/131332#132155 · In reply to: #131945

Hi


> The RFC has been updated to un-incorporate the strict-namespace 
> elements; if there are no further substantive comments, I would like to 
> open the vote in 2-ish weeks.

To put my remark in the (canceled) voting thread into the correct place, 
quoting myself from https://news-web.php.net/php.internals/132151:

> Without giving it detailed thought, I believe “Namespaced function, 
> Autoload namespaced function, Global fallback” (i.e. swap steps 2 and 
> 3) would result in much more predictable semantics already - the global 
> fallback would work just as before, it just wouldn't have autoloading 
> support. It's quite possible I'm changing my mind on that as well when 
> I think more about it […]

Best regards
Tim Düsterhus

---

## #132158 — Rowan Tommins [IMSoP] — 2026-07-31T21:57:06+00:00

URL: https://externals.io/message/131332#132158 · In reply to: #132155

Hi Tim, 

I posted this in the other thread, but I'm not sure it got through, so I'll repost here; apologies if both show up at once.


> > […]


Semantically, that makes most sense, but it leads to terrible performance for the global fallback case, unless there's some way to avoid multiple checks for the same namespaced function. That's why we keep going round in circles on the whole issue. 

I think Michael's "namespace autoloader" idea is a much cleaner way forward - it avoids the fallback issue without creating lots of extra special cases, and in reality "load a file with all functions for namespace Foo\Bar" is likely to be more common than "load a file which specifically defines function Foo\Bar\baz()".

Regards,

Rowan Tommins
[IMSoP]
