# RFC: Extended keyword support

- Status: Declined
- Authors: Bob Weinand, bobwei9@hotmail.com
- Date: 2013-09-14
- Version: 1.2
- Original: https://wiki.php.net/rfc/keywords_as_identifiers
- Page: https://externals.io/rfc/keywords_as_identifiers
- 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 extended keyword support patch be merged into master? (closed)

Yes: 5 · No: 11

Voters: bwoebi (Yes), cpriest (No), datibbaw (Yes), daverandom (Yes), derick (No), googleguy (No), guilhermeblanco (No), indeyets (Yes), jpauli (No), kalle (No), rasmus (No), remi (No), sebastian (No), seld (Yes), stas (No), zeev (No)

## Discussions on the mailing list

- [\[RFC\] Keywords as identifiers](https://externals.io/message/69146.md) — started on 2013-09-16, 15 messages
- [\[RFC\] \[Vote\] Keywords as identifiers](https://externals.io/message/69732.md) — started on 2013-10-21, 18 messages

---

## Introduction

This RFC aims to remove some restrictions which are due to the fact that keywords are not included in T\_STRING (especially for class const, method and class names).

This especially could be useful to preserve more BC compatibility whenever new keywords are introduced.

## What is now possible

- One might want to define an HTTP agent class. And would like to store some HTTP status constants:

```php
class HTTP {
    const CONTINUE = 100; // Works with patch
// But currently this fails with a parse error, because continue is a keyword.
    const SWITCHING_PROTOCOLS = 101;
    // etc. ...
}
```

- Building conditions with “and” or “or” methods

```php
class Cond {
    public static function and (...) { // using an "and" or "or" as name currently fails
        // some logic here
        return $andCondition;
    }
 
    public static function or (...) {
        // some logic here
        return $orCondition;
    }
}
 
Cond::and($cond1, $cond2);
```

- Prevents unnecessary use of \_\*\***\_call magic method (“-**\*\*&gt;keyword\_name\_for\_non\_static\_method()” works, but “public function keyword\_name\_for\_non\_static\_method() {}” currently fails)

```php
// Ugly, current code
class SomeClass {
    private $list = [];
 
    public function _list () {
        return $this->list;
    }
 
    public function __call ($func, $args) {
        if (method_exists($this, "_".$func)) {
            return call_user_func_array("_".$func, $args); // or some similar thing, if not underscores etc....
        }
        // some error handling here
    }
}
 
// How we could write it with the patch
class SomeClass {
    private $list = [];
 
    public function list () {
        return $this->list;
    }
}
```

## Details of proposal

Concretely this patch enables:

- all keywords for 
    - method names
    - class constant names
    - declare directive names
    - class names
    - trait names
    - interface names
    - goto label names
    - namespace names
- actual language features are preserved: 
    - a label (for goto) named *default* or *else* won't work (“default:” in switch or “else:” in alternative if structure)
    - a namespace named *namespace* won't work (a namespace name beginning with “namespace\\” is a relative namespace name)
    - a class constant named *class* can't be defined (“classname::class” has a special meaning)
    - ...

An example what is possible with this patch:

```php
namespace Class {
    class List {
        const default = 0;
        public $case = array(array(self::default));
 
        public static function echo (List $instance) {
            var_dump($instance->case);
        }
 
        public function new (array $entry) {
            $this->case[] = $entry;
            return $this;
        }
    }
}
 
namespace {
    \Class\List::echo((new Class\List)->new(array(1)));
}
```

### Typehints

Currently when using array or callable as typehint, the old behaviour is preferred over comparing if it's a class/interface named array or callable. I'm not sure if we should just allow both in this special case.

## Implementation

The transformation of alphabetic tokens to a T\_STRING is done in lexer (post-processing output of lexer).

Initially it was done in parser, but that had a few disadvantages:

- more restricted support for keywords
- output of token\_get\_all() and highlight\_\*() functions was still using the unconverted tokens

That is also why performance is affected, as it is some code which needs to be run on every token.

## Impact on performance

There is a slight decrease in *compilation performance* of up to 10% in worst case. So, actually, when used with opcache (execution only), any impact shouldn't be noticeable.

For that benchmark I used an 1.5 megabyte big file wrapped in an *if (false)* (so that nothing is executed): <https://raw.github.com/nikic/PHP-Parser/master/lib/PHPParser/Parser.php>

Compare actual run time:

```
time ./sapi/cli/php -r 'for($i=0;$i++<5000;)require "Parser.php";'
real	0m33.132s
user	0m32.816s
sys	0m0.313s
```

To run time with patch applied:

```
time ./sapi/cli/php -r 'for($i=0;$i++<5000;)require "Parser.php";'
real	0m36.720s
user	0m36.400s
sys	0m0.316s
```

## Proposed PHP Version(s)

This RFC should go into next PHP 5.x.

## Patch

- The patch is against master
- Pull request is at <https://github.com/php/php-src/pull/438>

## References

- Mailing List thread at <http://markmail.org/message/7rn4mbwkbytqa3ig>

## Rejected Features

- Initially the patch contained also some support for functions and constants which was removed later due to some resulting syntactic inconsistencies

## Vote

**Vote: Should the extended keyword support patch be merged into master?** — Yes: 5 · No: 11 (closed)

Deadline was Monday, 28th october 2013.

## Versions

- 1.0: Initial proposal (16.9.2013)
- 1.1: Added some more examples (18.9.2013)
- 1.2: Removed some restrictions (now all keywords are permitted except the ones which would conflict with the existing language) (16.10.2013)
