Почему использование класса с префиксом пространства имен со сложным фигурным синтаксисом в моей вспомогательной функции вызывает синтаксическую ошибку?

Я добавил файл вспомогательной функции в composer.json сразу после записи psr-4

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

но выдает синтаксическую ошибку:

<?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
    }
}

Ошибка синтаксического анализа: синтаксическая ошибка, неожиданный токен "\"

Если я использую любую существующую актуальную модель, она работает: $entity = \App\Models\Foobar. В моем коде есть несколько случаев, когда сложный фигурный синтаксис ({ $entityType }) не вызывает проблем, почему он здесь?


Редактировать

$class = '\\App\\Models\\' . $entityType; и $entity = "\\App\\Models\\$entityType"::find($id); работают, но я до сих пор не понимаю, почему. Во многих контроллерах я могу легко использовать \App\Models\{$entityType}::.

🤔 А знаете ли вы, что...
PHP обладает большим сообществом разработчиков и обширной документацией.


60
1

Ответ:

Решено

Синтаксическая ошибка возникает независимо от того, где находится ваш код.

Разница в том, что вспомогательный файл загружается и компилируется напрямую (автозагружается), в то время как класс контроллера загружается/компилируется только при вызове.

Это означает, что если вы возьмете класс (например, User::class) и добавите в него эту функцию.

class User
{
    public static function foo()
    {
        return 'bar';
    }

    public function entity_show($entityType, $id, $locale = null) {
        $entity = \App\Models\{ $entityType }::find($id); // syntax error
    }
}

Если вы запустите команду php artisan tinker, она не вызовет синтаксическую ошибку. Но если в laravel tinker запустить User::foo(), появится ошибка.

Чтобы динамически загружать класс, избегая синтаксической ошибки, сгенерируйте строку класса заранее.

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);
    }
}

Хотя я настоятельно рекомендую вам отказаться от использования вызовов динамических классов, поскольку это будет мешать поиску использования классов, когда вы захотите их изменить. Простой способ для вашей функции - передать объект для поиска в вашей функции (что также позволит избежать проверки существования объекта в БД внутри этой функции)

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();
        }

        //...
    }
}