Le 10/07/2026 à 17:41, Holly Schilling a écrit :
The two other RFCs imply extensions will need to be imported via manual 
require/require_once calls, therefore package maintainers declaring extensions will have 
to use the "autoload.files" composer option. It works, but it will add an 
overhead (wasting time in file load and wasting memory usage) on extensions that are 
declared but not used.
With the inclusion of the Visibility RFC, explicit `require` or `require_once` 
is not necessary. The `use extension` syntax replaces it. The consequence of 
this is that extension methods are only visible in scopes that explicitly want 
them. This prevents the from polluting globally.

If autoload was triggered when encountering "use extension", it would have the advantage of being 
explicit, but it's counter-intuitive: "use" statements shouldn't usually trigger anything and just 
serve as aliases for symbols referenced in the file, so it's inconsistent with current usage of the 
"use" keyword.
And if package maintainers don't use "autoload.files" to avoid the potentially unnecessary 
overhead, this means that userland code would be forced to write "require_once 'path/to/extension.php'; 
" in their own files, which is not at all what anyone would expect, and defeats the purpose of having a 
dependencies manager like Composer in the first place, even though "it works".
The new `use extension` syntax is a slightly different purpose than developers 
are used to with an ordinary `use` declaration, but it follows the same spirit. 
There is a thing not in this file that needs to be brought into scope.

Again: the "use extension" isn't bad per se, it's just that the "use" keyword *doesn't do anything*, and never has. It's just an alias. Adding "use extension", though being "slightly different" that just having "use", still means that it's gonna be on top of the PHP file, many IDEs already fold these statements for readability.

Something else I am thinking about changing the keyword and applying the extension to a class directly at the same time:


<?php
// vendor/foo/bar/src/Extension/RequestExtension.php

namespace Foo\Bar\Extension;

use Symfony\Component\HttpFoundation\IpUtils;
use Symfony\Component\HttpFoundation\Request;

extension RequestExtension for Request
{
    public function isBehindProxy(string $ip): bool
    {
        return IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), [$ip]);
    }
}

?>

<?php

// index.php

use Symfony\Component\HttpFoundation\Request;
use Foo\Bar\Extension\RequestExtension;

extend Request with RequestExtension;

$request = Request::createFromGlobals();

var_dump($request->isBehindProxy()); // works


We can imagine that the "extends A with B;" keyword is redundant, but it brings an advantage in the fact that an extension declares the "minimum" class it's capable of extending, but it could also declare no class at all (thus removing the "for ..." part of the extension's declaration).

In such case, the *user* determines which "maximum" class it will actually extend, and if there is a mismatch it could throw an error:

<?php

class StandaloneClass {}
interface SomeInterface {}
abstract class SomeClass {}
class SomeImpl implements SomeInterface {}
class SomeChild extends SomeClass {}
class LongerTree extends SomeClass {}
abstract class TransientClass implements SomeInterface {}
class LastImpl extends TransientClass {}

// Extends nothing in particular, behaves just like an "external trait".
extension StandaloneExtension { /* ... */ }

// Can be used only if the extended class has the structure in its tree.
extension InterfaceExtension for SomeInterface { /* ... */ }
extension ClassExtension for SomeClass { /* ... */ }

extend StandaloneClass with StandaloneExtension; // Works
extend SomeImpl with InterfaceExtension; // Works
extend SomeChild with ClassExtension; // Works
extend LastImpl with InterfaceExtension; // Works: LastImpl -> TransientClass -> SomeInterface

extend StandaloneClass with InterfaceExtension; // Error: "StandaloneClass" does not extend nor implement "SomeInterface" extend StandaloneClass with ClassExtension; // Error: "StandaloneClass" does not extend nor implement "SomeClass"


The "extend ... with ..." is clearer on what it does, userland has a bit more control, but extension defines its rules.

WDYT?

Reply via email to