====== Request for Comments: Class Name Resolution As Scalar Via "class" Keyword ====== * Version: 1.0 * Date: 2012-04-17 * Author: Ralph Schindler * Status: Implemented in PHP 5.5 * First Published at: http://wiki.php.net/rfc/class_name_scalars ===== Introduction ===== This RFC proposes to add a new ''ClassName::class'' syntax, which provides the fully qualified class name as a string. ===== Use case ===== Class names in strings have to be fully qualified in PHP. It is not possible to utilize aliases registered through ''use'' statements: use A\Namespaced\ClassName; // this will try to create a mock of the global class ClassName, not // of the aliased class A\Namespaced\ClassName $mock = $this->getMock('ClassName'); ''ClassName::class'' allows the programmer to easily obtain the fully qualified class name from an aliased name: use A\Namespaced\ClassName; // ClassName::class resolves to 'A\Namespaced\ClassName' $mock = $this->getMock(ClassName::class); ==== Real World Usage Scenarios ==== 1. PHPUnit's Mocking use MyVendor\SomeComponent\TargetSubNs; // inside a test case $this->getMock(TargetSubNs\Foo::class); // as opposed to $this->getMock('MyVendor\SomeComponent\TargetSubNs\Foo'); 2. Doctrine use MyVendor\SomeComponent\TargetEntityNs as Entity; // inside a test case $entityManager->find(Entity\User::class, 5); // as opposed to $entityManager->find('MyVendor\SomeComponent\TargetEntityNs\User', 5); 3. Any Real (auto-wiring || auto-instantiating) Dependency Injection Container use MyVendor\SomeComponent\TargetNs as T; // inside a test case $dic->newInstance(T\Foo::class); // as opposed to $dic->newInstance('MyVendor\SomeComponent\TargetEntityNs\Foo'); 4. General PHP Usage: use MyVendor\SomeComponent\TargetNs as T; // reflection $r = new ReflectionClass(T\Foo::class); // instead of new ReflectionClass('MyVendor\SomeComponent\TargetNs\Foo'); // class_exists, also applies to any php function that takes a class name (is_subclass_of, get_class_methods, etc) if (class_exists(T\Foo::class, true)) {} // instead of class_exists('MyVendor\SomeComponent\TargetNs\Foo') ===== Choice of syntax ===== The ''ClassName::class'' syntax was chosen because it can not clash with existing constants (as ''class'' is a keyword). The feature addition thus is fully backwards compatible. Furthermore the syntax resembles the semantically equivalent Java syntax ''ClassName.class''. Note: since this feature reuses T_CLASS/class keyword, it is case-insensitive. Therefore, Foo::class is semantically equivalent to Foo::Class, Foo::CLASS and the like. ===== More examples ===== From the test for the feature: --TEST-- class name as scalar from ::class keyword --FILE-- --EXPECTF-- In NS string(11) "Foo\Bar\Moo" Top string(11) "Foo\Bar\One" string(3) "Boo" string(7) "Bee\Bop" string(3) "Moo" object(Foo\Bar\One)#1 (0) { } string(11) "Foo\Bar\Two" string(11) "Foo\Bar\Two" string(11) "Foo\Bar\One" string(11) "Foo\Bar\Baz" Parent string(11) "Foo\Bar\Two" string(13) "Foo\Bar\Three" string(11) "Foo\Bar\One" string(11) "Foo\Bar\Baz" Compile Check string(13) "Foo\Bar\Three" string(11) "Foo\Bar\Baz" string(11) "Foo\Bar\One" string(11) "Foo\Bar\Two" ===== Considerations ===== One situation in need of a solution is what to do with ''self::class'', ''static::class'', and ''parent::class'' Do we: * Throw a compile error? * Resolve as best as possible, meaning error in non-class context, do a runtime lookup in a class context **Note:** (as of 1/18/13) In the current patch, the following resolutions take place: * self::class resolves the same as %%__CLASS__%% would * static::class resolves the same as get_called_class() would * parent::class resolves the same as get_parent_class() would, (in fact, would return false if not inherited.) * static::class & parent::class when used in compile-time only places (like method signatures), will throw an exception ===== Patch ===== * Pull Request located here: https://github.com/php/php-src/pull/187/files ===== Vote ===== * Yes * No Note: This Vote has been closed as the RFC will be moved back to discussion at the time being while the RFC and associated patch become more mature. ===== Changelog ===== * 2012-04-17 Initially created by Ralph Schindler * 2012-09-08 Updated RFC and added link to Pull Request (which addresses considerations and on-list questions) * 2013-01-18 Updated RFC to reflect design decisions, updated the test/example