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?