phpannotationsheredocphp-8class-constants

Why are class constants not allowed in heredoc?


I want to use a class constant in heredoc which is used in an annotation, but that gives me an error.

class Example {
    #[MyAnnotation(schema:<<<YAML
    type: {${MyOtherClass::A_CONSTANT}}
    YAML)]
    function myFunction() {}
}

Result: PHP Fatal error: Constant expression contains invalid operations

This looks similar to another heredoc question, but as a const value, this should be available at compile time.

I could not find any information on why this should not work. I would be glad about finding a thread with people who encoutered similar problems or a more elegant way of writing a JSONSchema without chaining multiple heredocs. Of course, I could just use strings.

Why can class constants be used in heredoc in normal expressions, but not in annotations.

This is my current workaround in PHP 8.1:

class Example {
    #[MyAnnotation(schema:<<<YAML
    type: 
    YAML . MyOtherClass::A_CONSTANT)]
    function myFunction() {}
}

Solution

  • It's just not possible in the language as is. There are discussions on string interpolations changes (see comments), but not in the style I thought would be possible.

    A number of other languages use ${foo} style string interpolation, most notably bash and JavaScript (in template literals). However, its behavior is different from that in PHP. In PHP, that syntax means variable variables. In JavaScript, it supports arbitrary expressions 2). In its current form, [Braces after the dollar sign (“${foo}”)] and [Variable variables] are of limited use, and confusing for users from other nearby languages as they behave quite differently.

    This is also where my confusion came from.


    Example of what variable variable means:

    class Example {
     const A_CONST = 'text';
    }
    
    $text = 'var';
    
    echo "{${Example::A_CONST}}";
    // prints out 'var'
    

    The content of the context is interpreted as a name of a variable, that needs to be in scope. This is in this case equivalent to echo "$text";.


    With this unholy hack it is possible to get the const value:

    echo "${!${''}=Example::A_CONST}";
    // prints out 'text'
    

    read here why