Reputation: 358
Can I create a namespace alias using PHP 8.1 functions such as class alias?
We named the default namespace module in our company as "Subcompany" and want it to become "Company" now, as it's use has been broadened.
A perfect answer would as little as possible overhead and also allow autoloading transparently. A concern is that tools such as Intelephense would understand this alias.
The project also uses composer, so an answer that rewrites namespaces using that would work too.
Upvotes: 3
Views: 1294
Reputation: 198118
Can I create a namespace alias using PHP 8.1 functions such as class alias?
Yes, and thinking: class_alias
was introduced with PHP 5.3 and its' new namespaces language feature. It has been created so that it is easier to migrate from the global namespace into namespaces - which actually is between namespaces.
However you would need to register a class alias for every old classes/interfaces/traits/enums to their new counterpart first.
My\Old\Lib\Name\Module\Submodule\Interface
My\Tiger\Lib\Name\Module\Submodule\Interface
The old lib is gone, and there now is the brand new Tiger lib. All their classes etc. can be mapped by just exchanging the namespace prefix ('My\Old\Lib\Name\' -> 'My\Tiger\Lib\Name'
).
This can done done at runtime already as PHP does most of the work for you.
Register an autoloader, that based on the old namespace prefix loads as the new namespace prefix and aliasing the class to the old name beforehand.
Example:
spl_autoload_register(
static function (string $class_name) {
static $old = 'My\\Old\\Lib\\Name\\';
static $new = 'My\\Tiger\\Lib\\Name\\';
// only operate on the old namespace
if (0 !== strpos($class_name, $old)) {
return;
}
$new_name = substr_replace($class_name, $new, 0, strlen($old));
class_alias($new_name, $class_name);
$exists = class_exists($new_name);
},
$throw = true, /* throw when registering fails */
$prepend = false /* only alias at fall-through */
);
This code is straight forward, just two remarks on the registration parameters:
$throw = true
: You want to stop your application immediately when the aliasing autoloader can not be registered as otherwise you would get strange "class not found" errors much much later.$prepend = false
: Only if there still is code that is using the old classnames, the callback should be invoked. The now standard code using the new namespace with standard autoloading therefore comes first.And perhaps noteworthy is the class_exists()
part:
$exists = class_exists($new_name);
it triggers the autoloading for the new class if it has not yet been loaded.
Tip: Use an assertive variant of it so that within development it throws where there is still code using the old namespace. Then you can gather information while migrating in a more planned manner:
... $new_name = substr_replace($class_name, $new, 0, strlen($old)); assert(false, "old namespace in use: $class_name"); class_alias($new_name, $class_name); $exists = class_exists($new_name); assert($exists, "aliasing old namespace failed for class: $class_name"); }, ...
(developers should have throwing assertions enabled, not the production setting in which assertions are completely ignored)
Once the autoloader is registered, old code will automagically load the new classes under the old alias.
use My\Old\Lib\Name\Module\Boring;
$boring = new Boring();
assert($boring instanceof My\Old\Lib\Name\Module\Boring);
var_dump(get_class($boring)); # string(31) "My\Tiger\Lib\Name\Module\Boring"
Upvotes: 3