rfc:class_name_scalars

This is an old revision of the document!


Request for Comments: Class Name Resolution As Scalar Via "class" Keyword

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:

<?php
 
namespace Foo\Bar {
    class Baz {}
    var_dump(Moo::class); // resolve in namespace
    class Box {
        public static function registerClassName($class = Baz::class) {
            var_dump($class);
        }
    }
    Box::registerClassName();
}
 
namespace {
    use Bee\Bop as Moo,
        Foo\Bar\Baz;
    var_dump(Baz::class); // resolve from use
    var_dump(Boo::class); // resolve in global namespace
    var_dump(Moo::class); // resolve from use as
    var_dump(\Moo::class); // resolve fully qualified
    $class = Baz::class; // assign class as scalar to var
    $x = new $class; // create new class from original scalar assignment
    var_dump($x);    
}
 
 
?>
--EXPECTF--    
string(11) "Foo\Bar\Moo"
string(11) "Foo\Bar\Baz"
string(11) "Foo\Bar\Baz"
string(3) "Boo"
string(7) "Bee\Bop"
string(3) "Moo"
object(Foo\Bar\Baz)#1 (0) {
}

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 9/8/12)

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.)

Patch

* Pull Request located here: https://github.com/php/php-src/pull/187/files

Vote

Should the ::class feature be merged to master?
Real name Yes No
aharvey (aharvey)  
hradtke (hradtke)  
ircmaxell (ircmaxell)  
kriscraig (kriscraig)  
levim (levim)  
lstrojny (lstrojny)  
pajoye (pajoye)  
patrickallaert (patrickallaert)  
reeze (reeze)  
sebastian (sebastian)  
seld (seld)  
Final result: 10 1
This poll has been closed.

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)
rfc/class_name_scalars.1347635745.txt.gz · Last modified: 2017/09/22 13:28 (external edit)