Search code examples
phplaravellaravel-9php-8

Why does using a namespace prefixed class with complex curly syntax in my helper function throw a syntax error?


I added a helper function file in composer.json right after the psr-4 entry

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Database\\Factories\\": "database/factories/",
        "Database\\Seeders\\": "database/seeders/"
    },
    "files": [
        "app/Http/Helpers/helpers.php"
    ]
},

but it throws a syntax error:

<?php

namespace App\Http\Helpers;

if (!function_exists('entity_url')) {
    function entity_show($entityType, $id, $locale = null) {
        if (is_null($locale) && function_exists('app')) {
            $locale = app()->getLocale();
        }

        $entity = \App\Models\{ $entityType }::find($id); // syntax error
    }
}

Parse error: syntax error, unexpected token "\"

If I use any existing actual Model it works: $entity = \App\Models\Foobar. I have several cases in my code where the complex curly syntax ({ $entityType }) is no problem, why is it here?


Edit

$class = '\\App\\Models\\' . $entityType; and $entity = "\\App\\Models\\$entityType"::find($id); work, I still dont understand why though. Throughout many controllers I can easily use \App\Models\{$entityType}::.


Solution

  • There is a syntax error no matter where your code is.

    The difference is that the helper file is loaded and compiled directly (autoloaded) while the controller class will only be loaded/compiled when called.

    Means, if you take a class (User::class for example) and add that function to it.

    class User
    {
        public static function foo()
        {
            return 'bar';
        }
    
        public function entity_show($entityType, $id, $locale = null) {
            $entity = \App\Models\{ $entityType }::find($id); // syntax error
        }
    }
    

    If you run the command php artisan tinker it will not trigger the syntax error. But if in laravel tinker you run User::foo() the error will show up.

    To dynamically load you class avoiding any syntax error, generate the class string in advance

    if (!function_exists('entity_url')) {
        function entity_show($entityType, $id, $locale = null) {
            if (is_null($locale) && function_exists('app')) {
                $locale = app()->getLocale();
            }
    
            $entity = ('\App\Models\\' . $entityType)::find($id);
        }
    }
    

    Though I highly suggest you differ from using dynamic class calls since it will hinder searching for class uses when you want to change them. A simple way for your function is to pass the entity to be looked up in your function (which will also avoid having to check for the entity existence in DB inside this function)

    use Illuminate\Database\Eloquent\Model;
    
    if (!function_exists('entity_url')) {
        function entity_show(Model $entity, $locale = null) {
            if (is_null($locale) && function_exists('app')) {
                $locale = app()->getLocale();
            }
    
            //...
        }
    }