rfc:class_name_scalars

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
rfc:class_name_scalars [2012/04/17 14:30] – created ralphschindlerrfc:class_name_scalars [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
-====== Request for Comments: How to write RFCs ======+====== Request for Comments: Class Name Resolution As Scalar Via "class" Keyword ======
   * Version: 1.0   * Version: 1.0
   * Date: 2012-04-17   * Date: 2012-04-17
   * Author: Ralph Schindler <ralph.at.ralphschindler.com>   * Author: Ralph Schindler <ralph.at.ralphschindler.com>
-  * Status: Under Discussion+  * Status: Implemented in PHP 5.5
   * First Published at: http://wiki.php.net/rfc/class_name_scalars   * First Published at: http://wiki.php.net/rfc/class_name_scalars
  
 ===== Introduction ===== ===== Introduction =====
  
-Reuse the "class" keyword in order to provide class name resolution according to current namespace and use rules.+This RFC proposes to add a new ''ClassName::class'' syntax, which provides the fully qualified class name as a string.
  
-===== Proposal =====+===== Use case ===== 
 + 
 +Class names in strings have to be fully qualified in PHP. It is not possible to utilize aliases registered through ''use'' statements: 
 + 
 +<code php> 
 +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'); 
 +</code> 
 + 
 +''ClassName::class'' allows the programmer to easily obtain the fully qualified class name from an aliased name: 
 + 
 +<code php> 
 +use A\Namespaced\ClassName; 
 + 
 +// ClassName::class resolves to 'A\Namespaced\ClassName' 
 +$mock = $this->getMock(ClassName::class); 
 +</code> 
 + 
 +==== Real World Usage Scenarios ==== 
 + 
 +1. PHPUnit's Mocking 
 + 
 +<code php> 
 + 
 +use MyVendor\SomeComponent\TargetSubNs; 
 + 
 +// inside a test case 
 +$this->getMock(TargetSubNs\Foo::class); 
 +// as opposed to 
 +$this->getMock('MyVendor\SomeComponent\TargetSubNs\Foo'); 
 +</code> 
 + 
 +2. Doctrine 
 + 
 +<code php> 
 + 
 +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); 
 + 
 +</code> 
 + 
 +3. Any Real (auto-wiring || auto-instantiating) Dependency Injection Container 
 + 
 +<code php> 
 + 
 +use MyVendor\SomeComponent\TargetNs as T; 
 + 
 +// inside a test case 
 +$dic->newInstance(T\Foo::class); 
 +// as opposed to 
 +$dic->newInstance('MyVendor\SomeComponent\TargetEntityNs\Foo'); 
 + 
 +</code> 
 + 
 +4. General PHP Usage: 
 + 
 +<code php> 
 + 
 +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'
 + 
 +</code> 
 +===== 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: From the test for the feature:
  
 <code php> <code php>
 +
 +--TEST--
 +class name as scalar from ::class keyword
 +--FILE--
 <?php <?php
  
 namespace Foo\Bar { namespace Foo\Bar {
-    class Baz {} +    class One 
-    var_dump(Moo::CLASS)// resolve in namespace +        // compile time constants 
-    class Box +        const A = self::class; 
-        public static function registerClassName($class = Baz::class) { +        const B = Two::class; 
-            var_dump($class);+    } 
 +    class Two extends One 
 +        public static function run() { 
 +            var_dump(self::class); // self compile time lookup 
 +            var_dump(static::class); // runtime lookup 
 +            var_dump(parent::class); // runtime lookup 
 +            var_dump(Baz::class); // default compile time lookup
         }         }
     }     }
-    Box::registerClassName();+    class Three extends Two { 
 +        // compile time static lookups 
 +        public static function checkCompileTime( 
 +            $one = self::class, 
 +            $two = Baz::class, 
 +            $three = One::A, 
 +            $four = self::B 
 +        ) { 
 +            var_dump($one, $two, $three, $four); 
 +        } 
 +    } 
 +    echo "In NS\n"; 
 +    var_dump(Moo::CLASS); // resolve in namespace
 } }
  
 namespace { namespace {
     use Bee\Bop as Moo,     use Bee\Bop as Moo,
-        Foo\Bar\Baz+        Foo\Bar\One; 
-    var_dump(Baz::class); // resolve from use+    echo "Top\n"
 +    var_dump(One::class); // resolve from use
     var_dump(Boo::class); // resolve in global namespace     var_dump(Boo::class); // resolve in global namespace
     var_dump(Moo::CLASS); // resolve from use as     var_dump(Moo::CLASS); // resolve from use as
     var_dump(\Moo::Class); // resolve fully qualified     var_dump(\Moo::Class); // resolve fully qualified
-    $class = Baz::class; // assign class as scalar to var+    $class = One::class; // assign class as scalar to var
     $x = new $class; // create new class from original scalar assignment     $x = new $class; // create new class from original scalar assignment
-    var_dump($x);    +    var_dump($x); 
 +    Foo\Bar\Two::run(); // resolve runtime lookups 
 +    echo "Parent\n"; 
 +    Foo\Bar\Three::run(); // resolve runtime lookups with inheritance 
 +    echo "Compile Check\n"; 
 +    Foo\Bar\Three::checkCompileTime();
 } }
- 
  
 ?> ?>
---EXPECTF--    +--EXPECTF-- 
 +In NS
 string(11) "Foo\Bar\Moo" string(11) "Foo\Bar\Moo"
-string(11) "Foo\Bar\Baz" +Top 
-string(11) "Foo\Bar\Baz"+string(11) "Foo\Bar\One"
 string(3) "Boo" string(3) "Boo"
 string(7) "Bee\Bop" string(7) "Bee\Bop"
 string(3) "Moo" string(3) "Moo"
-object(Foo\Bar\Baz)#1 (0) {+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"
 </code> </code>
 +
 +===== Considerations =====
 +
 +One situation in need of a solution is what to do with ''self::class'', ''static::class'', and ''parent::class''
 +
 +Do we:
 +
 +  * <del>Throw a compile error?</del>
 +  * <del>Resolve as best as possible, meaning error in non-class context, do a runtime lookup in a class context</del>
 +
 +**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 ===== ===== Patch =====
  
-Patch located here: https://github.com/ralphschindler/php-src/compare/master...feature/class-name-scalar+Pull Request located here: https://github.com/php/php-src/pull/187/files 
 + 
 +===== Vote =====
  
  
 +<doodle title="Should the ::class feature be merged to master?" auth="ralphschindler" voteType="single" closed="true">
 +   * Yes
 +   * No
 +</doodle>
  
 +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 ===== ===== Changelog =====
  
-* 2012-04-17 Initially created by Ralph Schindler+  * 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
  
rfc/class_name_scalars.1334673026.txt.gz · Last modified: 2017/09/22 13:28 (external edit)