====== PHP RFC: Extended keyword support ====== * Version: 1.2 * Date: 2013-09-14 * Author: Bob Weinand, bobwei9@hotmail.com * Status: Declined * The implementation was creating too much need for maintenance etc. Don't duplicate that proposal without a better implementation. * First Published at: http://wiki.php.net/rfc/keywords_as_identifiers ===== 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: 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 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 ("-****>keyword_name_for_non_static_method()" works, but "public function keyword_name_for_non_static_method() {}" currently fails) // 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: 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 ===== * Yes * No 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)