rfc:class_name_scalars

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
rfc:class_name_scalars [2012/04/17 15:37] – Clarify use case nikicrfc:class_name_scalars [2013/01/19 01:50] nikic
Line 3: Line 3:
   * 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
  
Line 31: Line 31:
 </code> </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 ===== ===== 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. 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 equivalent Java syntax ''ClassName.class'.+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 ===== ===== More examples =====
Line 42: Line 97:
  
 <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.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1