Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Added support for keywords for class/method/label/declare/namespace/class const names #438

Closed
wants to merge 9 commits into
from

Conversation

Projects
None yet
4 participants
Contributor

bwoebi commented Sep 11, 2013

This patch adds possibility to use keywords at some places where previously were only T_STRING's allowed.

Example:

class List { // T_LIST, is now enabled
    public function default() { // T_DEFAULT
        // do some action
    }
}

For further examples see the rfc at https://wiki.php.net/rfc/keywords_as_identifiers

The goal of the patch is to limit less the user's choice of names for labels, classes, functions, namespaces etc.

Internals discussion at http://marc.info/?l=php-internals&m=137893452326358&w=2


Possible constructs (with string being a T_STRING or a keyword):

string::string;
string::string();
$var->string;
$var->string();
(modifier)* function string() { // methods
function T_STRING ((string) $var, ...) // the optional typehint
declare(string = ..., ...);
(namespace) \(string\)*string;
use string as (modifier) string; // namespace aliasing
new string;
class string (extends string) (implements string, ...) {
trait string (extends string) (implements string, ...) {
interface string (extends string, ...) {
string::…;
string: // label for goto
goto string;

What still is impossible: (as function names and constants remain unaffected)

keyword(); // fcall
keyword; // constant

@nikic nikic and 1 other commented on an outdated diff Sep 15, 2013

Zend/zend_compile.c
@@ -7002,9 +7008,11 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{
lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));
if (((Z_STRLEN_P(name) == sizeof("self")-1) &&
- !memcmp(lcname, "self", sizeof("self")-1)) ||
- ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
- !memcmp(lcname, "parent", sizeof("parent")-1))) {
+ !memcmp(lcname, "self", sizeof("self")-1)) ||
+ ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
+ !memcmp(lcname, "parent", sizeof("parent")-1)) ||
+ ((Z_STRLEN_P(name) == sizeof("static")-1) &&
+ !memcmp(lcname, "parent", sizeof("static")-1))) {
@nikic

nikic Sep 15, 2013

Owner

nit: should be static

@bwoebi

bwoebi Sep 15, 2013

Contributor

Hmpf, fixed. Had that already fixed locally, but forgotten to commit it.

@Majkl578 Majkl578 referenced this pull request Sep 22, 2013

Closed

anon class objects #470

bwoebi added some commits Oct 4, 2013

Moved keyword handling from parser to lexer
Actually, having it in parser, also caused tokenizer and highlighter to return the keyword tokens instead of a T_STRING token which might confuse parsers (and lead this way to a BC break)
Also this way we do not need to maintain a fixed list in parser which needs to be updated on every addition/modification of keywords
Furthermore it allows more control over tokens before they are passed to parser (for future features...)
Optimized
Stored some values in variables (which are then stored during function execution in registers) instead of refetching them everytime

@smalyshev smalyshev and 1 other commented on an outdated diff Oct 16, 2013

Zend/tests/bug43343.phpt
@@ -2,10 +2,12 @@
Bug #43343 (Variable class name)
--FILE--
<?php
-namespace Foo;
-class Bar { }
+class if {
@smalyshev

smalyshev Oct 16, 2013

Contributor

why replace a working test with something completely different? If we need to test for if as class name, we can add different test, but that's not what this test was about.

@bwoebi

bwoebi Oct 16, 2013

Contributor

@smalyshev actually a class named namespace is supported. So the test was superfluous in it's old state.

@smalyshev

smalyshev Oct 16, 2013

Contributor

@bwoebi if it's supported, change the outcome of the test, why rewrite it to something completely different testing something else not related to the bug?

@bwoebi

bwoebi Oct 16, 2013

Contributor

@smalyshev good question… Don't remember why I had changed the test. Reverted test now and updated expectf to match actual state.

@smalyshev smalyshev commented on an outdated diff Oct 16, 2013

Zend/zend_compile.c
@@ -201,6 +201,11 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
zend_stack_init(&CG(context_stack));
CG(encoding_declared) = 0;
+ CG(tokenbufptr) = -1;
+ CG(tokenbuffer) = emalloc(sizeof(token_buf) * ((CG(tokenbufsize) = ZEND_INIT_TOKEN_BUF_SIZE) + 1));
@smalyshev

smalyshev Oct 16, 2013

Contributor

I don't think we need to be clever here. Why not just assign CG(tokenbufsize) = ZEND_INIT_TOKEN_BUF_SIZE separately? It would be much more readable.

@smalyshev smalyshev commented on an outdated diff Oct 16, 2013

Zend/zend_language_parser.y
@@ -536,9 +535,7 @@ non_empty_parameter_list:
optional_class_type:
/* empty */ { $$.op_type = IS_UNUSED; }
- | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_ARRAY; }
- | T_CALLABLE { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_CALLABLE; }
- | fully_qualified_class_name { $$ = $1; }
+ | class_name { if ((Z_STRLEN($1.u.constant) == 5 && !strncasecmp(Z_STRVAL($1.u.constant), "array", 5)) || (Z_STRLEN($1.u.constant) == 8 && !strncasecmp(Z_STRVAL($1.u.constant), "callable", 8))) { $$.op_type = IS_CONST; efree(Z_STRVAL($1.u.constant)); switch (Z_STRLEN($1.u.constant)) { case 5: Z_TYPE($$.u.constant) = IS_ARRAY; break; case 8: Z_TYPE($$.u.constant) = IS_CALLABLE; break; } } else { $$ = $1; } }
@smalyshev

smalyshev Oct 16, 2013

Contributor

I think it may be better to take it out as a function. As an one-line expression it is not readable and if we'd ever need to modify it it would be very easy to do it wrong. It probably also has some reuse potential.

@smalyshev smalyshev commented on an outdated diff Oct 16, 2013

Zend/zend_language_scanner.l
+ }
+ default:
+ if (LEX_IS_BUF_ALPH_TOKEN(buf_one)) {
+ LEX_CONVERT_BUF_STRING(buf_one);
+ }
+ }
+ }
+ /* handling of multiple comma separated T_USE */
+ if (CG(tokenbuf_mode) == LEX_USE_TOKEN_MODE && LEX_IS_CUR_ALPH_TOKEN() && buf_one_token == ',') {
+ LEX_CONVERT_CUR_STRING();
+ }
+
+ /* Handling of T_HALT_COMPILER; might cause memory leaks if not handled */
+ if (buf_one_token == T_HALT_COMPILER && retval == '(') {
+ LEX_BUF_ADD
+ } else if (buf_two_token == T_HALT_COMPILER && buf_one_token == '(' && retval == ')') {
@smalyshev

smalyshev Oct 16, 2013

Contributor

these two branches seem to have the same code inside, why there's two branches and not just one if with || condition?

Comment on behalf of nikic at php.net:

Closing as this RFC failed and there now is a new one.

@php-pulls php-pulls closed this Feb 28, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment