# RFC: Resolve class names to scalars via class keyword

- Status: Implemented (PHP 5.5)
- Authors: Ralph Schindler <ralph.at.ralphschindler.com>
- Date: 2012-04-17
- Version: 1.0
- Original: https://wiki.php.net/rfc/class_name_scalars
- Page: https://externals.io/rfc/class_name_scalars
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Votes

### Should the ::class feature be merged to master? (closed)

Yes: 10 · No: 1

Voters: aharvey (Yes), hradtke (Yes), ircmaxell (Yes), kriscraig (Yes), levim (Yes), lstrojny (Yes), pajoye (Yes), patrickallaert (No), reeze (Yes), sebastian (Yes), seld (Yes)

## Discussions on the mailing list

- [\[VOTE\] ::class feature to resolve namespaced class names to scalars](https://externals.io/message/62949.md) — started on 2012-09-11, 33 messages

---

## 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:

```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');
```

`ClassName::class` allows the programmer to easily obtain the fully qualified class name from an aliased name:

```php
use A\Namespaced\ClassName;
 
// ClassName::class resolves to 'A\Namespaced\ClassName'
$mock = $this->getMock(ClassName::class);
```

### Real World Usage Scenarios

1\. PHPUnit's Mocking

```php
use MyVendor\SomeComponent\TargetSubNs;
 
// inside a test case
$this->getMock(TargetSubNs\Foo::class);
// as opposed to
$this->getMock('MyVendor\SomeComponent\TargetSubNs\Foo');
```

2\. Doctrine

```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);
```

3\. Any Real (auto-wiring \|\| auto-instantiating) Dependency Injection Container

```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');
```

4\. General PHP Usage:

```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')
```

## 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
--TEST--
class name as scalar from ::class keyword
--FILE--
<?php
 
namespace Foo\Bar {
    class One {
        // compile time constants
        const A = self::class;
        const B = Two::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
        }
    }
    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 {
    use Bee\Bop as Moo,
        Foo\Bar\One;
    echo "Top\n";
    var_dump(One::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 = One::class; // assign class as scalar to var
    $x = new $class; // create new class from original scalar assignment
    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--
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 &amp; 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

**Vote: Should the ::class feature be merged to master?** — Yes: 10 · No: 1 (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)
- 2013-01-18 Updated RFC to reflect design decisions, updated the test/example
