31

Why would we use the class_alias function? For example:

Class Test {
 public function __construct(){
   echo "Class initialized"; 
 }
}

class_alias("Test", "AnotherName"); 

$instance = new AnotherName();   # equivalent to $instance = new Test();

According to the manual, "The aliased class is exactly the same as the original class."

What is this useful for?

Burhan Ali
  • 2,258
  • 1
  • 28
  • 38
Daryl Gill
  • 5,464
  • 9
  • 36
  • 69
  • 3
    an interesting use case is [conditional imports](http://www.php.net/manual/en/function.class-alias.php#111585) – bitWorking Jul 20 '13 at 17:54
  • Because if don't like to implements Parent class and class_alias show same property as implements do. ex. var_dump($instance instanceof Test);//true – Shushant Jul 27 '13 at 05:51
  • `class_alias` is a typical what-the-hell thing in PHP: don't use it. It generates unremovable garbage aliases. Also note that you can't pass an aliased-class-instantiated object to an original-class-hint parameter (uhh!). – Dávid Horváth Apr 20 '17 at 11:01
  • Yes you can, an instance of the aliased name passes method type hinting & instanceof tests. – Christoffer Bubach Oct 06 '18 at 12:12

3 Answers3

54

Surprisingly, nobody has mentioned the obvious reason why one would do this: the use keyword can only be used in the outmost scope, and is processed at compile-time, so you can't use Some\Class based on some condition, nor can it be block-scoped:

namespace Foo;
if (!extension_loaded('gd'))
{
    use Images\MagicImage as Image;
}
else
{
    use Images\GdImage as Image;
}
class ImageRenderer
{
    public function __construct(Image $img)
    {}
}

This won't work: though the use statements are in the outmost scope, these imports are, as I said before, performed at compile-time, not run-time. As an upshot, this code behaves as though it was written like so:

namespace Foo;
use Images\GdImage as Image;
use Images\MagicImage as Image;

Which will produce an error (2 class with the same alias...)
class_alias however, being a function that is called at run-time, so it can be block scoped, and can be used for conditional imports:

namespace Foo;
if (!extension_loaded('gd'))
{
    class_alias('Images\\MagicImage', 'Image');
}
else
{
    class_alias('Images\\GdImage','Image');
}
class ImageRenderer
{
    public function __construct(Image $img)
    {}
}

Other than that, I suspect the main benefit of class_alias is that all code written, prior to PHP 5.3 (which introduced namespaces) allowed you to avoid having to write things like:

$foo = new My_Lib_With_Pseudo_Name_Spaces_Class();

Instead of having to refactor that entire code-base and create namespaces, It's just a lot easier to add a couple of:

class_alias('My_Lib_With_Pseudo_Name_Spaces_Class', 'MyClass');

To the top of the script, along with some //TODO: switch to Namespaces comments.

Another use case might be while actually transferring these classes to their namespaced counterparts: just change the class_alias calls once a class has been refactored, the other classes can remain intact.
When refactoring your code, chances are you're going to want to rethink a couple of things, so a use-case like aichingm suggested might not be too far fetched.

Last thing I can think of, but I haven't seen this yet, is when you want to test some code with a mock object, you might use class_alias to make everything run smoothly. However, if you have to do this, you might aswell consider the test a failure, because this is indicative of badly written code, IMO.

Incidently, just today I came across another use-case for class_alias. I was working on a way to implement a lib, distilled from a CLI tool for use in a MVC based web-app. Some of the classes depended on an instance of the invoked command to be passed, from which they got some other bits and bolts.
Instead of going through the trouble of refactoring, I decided to replace the:

use Application\Commands\SomeCommand as Invoker;

Statements with:

if (\PHP_SAPI === 'cli')
{
    class_alias('\\Application\\Commands\\SomeCommand', 'Invoker');
}
else
{
    class_alias('\\Web\\Models\\Services\\SomeService', 'Invoker');
}

and, after a quick :%s/SomeCommand/Invoker/g in vim, I was good to go (more or less)

Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • So essentially, this is to keep compatibility between newer and older OOP based code, since the introduction of namespaces? – Daryl Gill Jul 30 '13 at 20:31
  • @DarylGill: Yes, and to allow you to block-scope imports. You can't, for instance, put a `use` statement inside a class (which has its own scope), but you can use a `class_alias` call inside a given scope. You can also use `class_alias` instead of `use` to determine what object to use. If you write a lib, that contains classes to manipulate images, but the machine on which that code needs to run hasn't got the `gd` extension installed/loaded, but it does have imageMagic installed, you can use `class_alias` to import the dependency that will work on that machine (see my first example) – Elias Van Ootegem Jul 31 '13 at 06:50
  • @DarylGill: Oh, and perhaps, in due time, it will be possible to import full namespaces using PHP, in which case `class_alias` might be used to override a particular subclass of the imported namespace: `use Namespace\Foo\*;`, suppose `Namespace\Foo\Bar` needs to be overridden with `Namespace\Bar\Bar`, you could write `use Namespace\Foo\*; use Namespace\Bar\Bar as BBar; class_alias('BBar', 'Bar');` or something, but that's _if_ importing an entire NS ever gets supported – Elias Van Ootegem Jul 31 '13 at 10:18
  • I wish I offered a higher bounty for this response. Thank you – Daryl Gill Jul 31 '13 at 11:52
  • @DarylGill: Ah, a bounty is useful to get a better answer, and its a nice _"bit on the side"_, thanks for awarding it too me ;-) – Elias Van Ootegem Jul 31 '13 at 11:54
  • You can't remove aliases. So all of the pseudo-local class aliases letter the global symbol table. You can not use `Invoker` or any other simple name twice int the entire project, its subprojects, and dependencies included from anywhere in the universe. – Dávid Horváth Mar 09 '17 at 15:12
9

Think of this the other way. There is a library and it contains a class called MySq, as the library moves on in development they think 'oh maybe we should just make one database class' so the rewrite the class and call it 'DatabaseConnection' it has the same functions as the MySql class but it can also handle Sql and MsSql. As time goes on and they release the new version 'PHPLib2'. The developer has now two options: 1, tell the users to change from MySql to DatabaseConnection or 2, the developer uses

class_alias("DatabaseConnection","MySql"); 

and just mark the class MySql as deprecated.

tltr;

To keep version compatibility!

aichingm
  • 738
  • 2
  • 7
  • 15
  • 1
    +1 really useful..but it could be dangerous. `get_class` would return `DatabaseConnection`. – bitWorking Jul 20 '13 at 18:09
  • And, as expected in the world of PHP, you can not pass a `DatabaseConnection` to `foo(MySql $bar)` – Dávid Horváth Aug 17 '17 at 02:26
  • @DávidHorváth Of course you can't - the whole point is to do: `class_alias('DatabaseConnection', 'MySql'); $obj = new Mysql();` to get an object that will pass typehint & instanceof checks for MySql. Not to set up the alias and still try to use the original classname DatabaseConnection... -.-' – Christoffer Bubach Oct 06 '18 at 12:05
2

It can be used for:

  1. Changing strange class names of ext. scripts/sources (without the need to rewrite the code)
  2. Making class names shorter (the class alias can be used application wide)
  3. Moving classes to another namespace (@tlenss)
Pieter
  • 1,823
  • 1
  • 12
  • 16
  • 2
    3. Making classes available in another namespace – tlenss Jul 20 '13 at 17:47
  • If the code is being written by the developer.. He/she would use a less complicated class name to base their code around, even then.. The lengh/complexity of the class name should not be taken into account, because: `$Test = new ClassName();` <- with this, `$Test` becomes the new placeholder for the class name – Daryl Gill Jul 20 '13 at 17:48
  • Of course, but if you need to initiate a new class multiple times in one page/script, I can imagine that it will be useful. – Pieter Jul 20 '13 at 17:50
  • @tlenss that's what [importing namespaces](http://www.php.net/manual/en/language.namespaces.importing.php) do – bitWorking Jul 20 '13 at 18:00
  • @tlenss no this wouldn't work as class Test has to be in the same namespace as you are using class_alias for you propose you would use `use My\Namespace\Test as AnotherName;` sorry @redreggae you are too fast – aichingm Jul 20 '13 at 18:02
  • @redreggae @aichingm Maybe it's not the desired way. But this does seem to work `class_alias('Foo\bar', 'Bar\bla');` – tlenss Jul 20 '13 at 18:22