PHP — создание «нового» класса и аргументов, заданных в строке

#php #class #variables

#php #класс #переменные

Вопрос:

У меня есть класс и аргументы, установленные в переменной, подобной этой:

 $myVar = 'ApiMyClass(DateTimeInterface::RFC3339_EXTENDED)';
 

Мне нужно сделать new из этой переменной.

Я пробовал несколько решений, и в конце new класс был решен, но я не могу передать аргумент.

Мой код:

 <?php

$myVar = 'ApiMyClass(DateTimeInterface::RFC3339_EXTENDED)';
$className = substr($myVar, 0, strpos($myVar, "(")); // $className will be: ApiMyClass
if (class_exists($className)) {
    preg_match('/((.*?))/', $myVar, $classArguments); $classArguments will be: DateTimeInterface::RFC3339_EXTENDED
    $obj = new $className($classArguments[1]); // it doesn't work
}
 

проблема в том, что $classArguments[1] это передается как string моему классу. Ниже разница:

 // It works
$p = DateTimeInterface::RFC3339_EXTENDED;
var_dump($p);

// and return
string(15) "Y-m-dTH:i:s.vP"
 
 // It doesn't work
$p = "DateTimeInterface::RFC3339_EXTENDED";
var_dump($p);

// return
string(36) "DateTimeInterface::RFC3339_EXTENDED"
 

вы можете мне помочь?

Спасибо.

Комментарии:

1. Могу я спросить ваш вариант использования? Я не могу придумать ни одного допустимого варианта использования, в котором вы могли бы получить такую строку.

Ответ №1:

New можно использовать только для создания экземпляра. Сделайте так, чтобы ваш конструктор ожидал этот формат даты по умолчанию, поэтому вам не нужно его передавать.

 class MyClass {
    public function __construct(string $dateFormat = DateTimeInterface::RFC3339_EXTENDED)
    {
    }
}

$var = 'MyClass';

$instance = new $var;
 
 $p = "DateTimeInterface::RFC3339_EXTENDED";
 

не сработает, потому что теперь это строка, а не значение константы.

Вы также можете передать что-то вроде этого

 class MyClass {
    public function __construct(string $something = '')
    {
        echo $something;
    }
}

$var = 'MyClass';
$text = 'Hello world';
$instance = new $var($text);
 

Привет, мир

Если вам нужна полная строка для анализа, попробуйте eval() , но не рекомендуется.

 $var = 'new MyClass("hello world");';
$instance = eval($var);
 

Привет, мир

или, но не рекомендуется.

 $var = 'MyClass("hello world")';
$instance = eval("new {$var};");
 

Привет, мир

Ответ №2:

Вы можете использовать constant функцию для получения значения константы.

Простой пример класса, который просто выводит значение параметра при инициализации.

 class MyClass
{
    function __construct($arg) {
        echo "$argn";
    }
}

new MyClass('anything'); // outputs "anything"
 

Это просто помощник, который получает имя класса и строку аргумента из строки, подобной вашей $myVar .

 function parseClassAndArgument(string $str): array {
    preg_match('/(.*)((.*))/', $str, $matches);
    [, $className, $argument] = $matches;
    return [$className, $argument];
}
 

Этот помощник позволяет вам передавать либо строковое значение, либо имя константы, и угадывает, какое из них основано на том, есть ли a :: в имени строки. Вы можете заменить это только constant($argument) частью, если вы знаете $myVar , что она всегда будет содержать постоянное имя.

 function parseArgValue(string $argument): string {
    return strpos($argument, '::') ? constant($argument) : $argument;
}
 

Это распознает, что $argument ссылается на константу, и выводит Y-m-dTH:i:s.vP

 $myVar = 'MyClass(DateTimeInterface::RFC3339_EXTENDED)';
[$className, $argument] = parseClassAndArgument($myVar);
new $className(parseArgValue($argument));
 

Это выводит строку foo как есть.

 $myVar = 'MyClass(foo)';
[$className, $argument] = parseClassAndArgument($myVar);
new $className(parseArgValue($argument));
 

Это упрощенный пример, который обрабатывает только один параметр для конструктора класса, но я надеюсь, что это поможет вам!

Комментарии:

1. Конечно, вы могли бы включить синтаксический анализ строки аргумента внутри конструктора класса; нет необходимости делать это вне класса.