Article::getClassName() or Article::className

I miss a feature in PHP, which would allow me to reference classes easily. For example in Java, if you have a class cz.juzna.abc.Acticle and you want to give it to a variable/method, you can reference it by cz.juzna.abc.Acticle.class.

In PHP, this can be done only by a string with class' name ("cz\juzna\abc\Article"), which is however a string and not a reference. For example IDE won't see it as usage of a class (it won't autocomplete, won't find it in usages, …). This makes it very easy to make errors or typos in such definitions, or to break the system while refactoring.

It may be difficult to extend PHP itself, but we can add this feature to Nette\Object:

abstract class Object {
  ...
  static function getClassName() {
    return get_called_class();
  }
}

With this, I can use cz\juzna\abc\Article::getClassName(), which is a piece of code; it's „alive“ and will fail if mistaken.

Advantages

  • No need for full namespaces, if you have use-statement for the class
  • Auto-completion in IDE; you start typing Rol and it offers RoleEntity for you
  • Go to definition or Ctrl+click works in IDE
  • Warnings in IDE if the class is misspelled
  • Found in „find usages“
  • Can be refactored
  • etc.

Summary: it's a live class now, instead of a dead string.

Patching PHP

This feature would make more sense if available in vanilla PHP, for every class and not only those extending Nette\Object. I experimented with PHP's source code and created a small patch which adds magic constant MyClass::className to every class. Available for PHP 5.3.8 here. It's not stable for production, rather as a proof of concept for developers to test, whether it's worth to have it.

I'm also experimenting with a magic constant MyClass::class which would contain MyClass' reflection object (similar to what we have in Java), but there are still some questions about this to be answered. Mainly, that such a constant must be in language core, while PHP's reflection is an extension (and core depending on an extension is not a very good idea). Any suggestions are welcome!

Experience

I added this to my Nette fork and have been using this for a month now, and it's so useful to have it in every class, with IDE's hints as well. Especially if you work with ORM like Doctrine.

If you're using ORM and if you type class names as strings often, try it for a while and you'll see ;)

Note: I also wrote a post on Nette forum regarding this issue.

You can leave a response, or trackback from your own site.

5 Responses to “Article::getClassName() or Article::className”

  1. I didn't like the ::getClassName() method, but I realy like idea of making it a constant.

    $class = MyClass::class;

    Realy nice!

  2. juzna.cz says:

    @HosipLan: I don't have this idea finished yet. In my opinion, MyClass::class should give again something „live“ (thus not a string with class name), but I'm not sure what. Should it be ReflectionClass? And I guess it should be the same instance everytime you access this constant – this may get more complicated… But will try

  3. Does ReflectionClass have

    __toString() { return $this->getName(); }

    method? If does, it could be returned from the constant.

  4. David Grudl says:

    Magic constant should work without autoloading.

    • juzna.cz says:

      You mean that MyClass::className should not invoke autoloading of MyClass? Why do you think so? It make sense as it would postpone loading of such class to point where it's really needed.

      But I think it may be appropriate for the class to be loaded, so that you'd get exception thrown in the place where you used invalid reference, instead of the place where the class gets instantiated for the first time (or used in another way).

      Of course, we can discuss this. And a good point, I haven't thought about it.

Leave a Reply