Создание экземпляра класса PHP со строкой

223

У меня есть два класса, class ClassOne { }и class ClassTwo {}. Я получаю строку, которая может быть "One"или "Two".

Вместо использования длинного switchвыражения, такого как:

switch ($str) {
    case "One":
        return new ClassOne();
    case "Two":
        return new ClassTwo();
}

Есть ли способ , что я могу создать экземпляр , используя строку, то есть new Class("Class" . $str);?

Joel
источник

Ответы:

484

Да, ты можешь!

$str = 'One';
$class = 'Class'.$str;
$object = new $class();

При использовании пространств имен укажите полное имя :

$class = '\Foo\Bar\MyClass'; 
$instance = new $class();

Другие интересные вещи, которые вы можете сделать в php:
Переменные :

$personCount = 123;
$varname = 'personCount';
echo $$varname; // echo's 123

И переменные функции и методы.

$func = 'my_function';
$func('param1'); // calls my_function('param1');

$method = 'doStuff';
$object = new MyClass();
$object->$method(); // calls the MyClass->doStuff() method. 
Боб Фэнджер
источник
1
Спасибо за примеры!
Джоэл
28
К вашему сведению, вы не можете частично использовать переменную. например. $my_obj = Package\$class_name();, Вместо этого вы должны$class_name = "Package\\" . $class_name; $my_obj = new $class_name();
Birla
14
Обратите внимание, что при использовании пространств имен вы должны указать полный путь:$className = '\Foo\Bar\MyClass'; $instance = new $className();
Giel Berkers
5
Там нет ложки ... только php.
Капитан Гипертекст
4
но один вопрос. Описанный выше метод можно использовать для создания нового экземпляра класса. Что если я захочу статически вызвать метод существующего класса? Я попытался следующим образом: $model = $user_model::find()->All(); где $user_modelнаходится переменная, содержащая строку вызываемого класса
Рамеш Парик
22

Вы можете просто использовать следующий синтаксис для создания нового класса (это удобно, если вы создаете фабрику ):

$className = $whatever;
$object = new $className;

В качестве (исключительно грубого) примера фабричного метода:

public function &factory($className) {

    require_once($className . '.php');
    if(class_exists($className)) return new $className;

    die('Cannot create new "' . $className . '" class - includes not found or class unavailable.');
}
Джон Паркер
источник
1
Вы не пропустите точку между именем класса и расширением? require_once($className.'php'); ->require_once($className.'.php');
J Quest
4

Скажем ClassOne, определяется как:

public class ClassOne
{
    protected $arg1;
    protected $arg2;

    //Contructor
    public function __construct($arg1, $arg2)
    {
        $this->arg1 = $arg1;
        $this->arg2 = $arg2;
    }

    public function echoArgOne
    {
        echo $this->arg1;
    }

}

Использование PHP Reflection;

$str = "One";
$className = "Class".$str;
$class = new \ReflectionClass($className);

Создайте новый экземпляр:

$instance = $class->newInstanceArgs(["Banana", "Apple")]);

Вызовите метод:

$instance->echoArgOne();
//prints "Banana"

Используйте переменную в качестве метода:

$method = "echoArgOne";
$instance->$method();

//prints "Banana"

Использование Reflection вместо простого использования необработанной строки для создания объекта дает вам лучший контроль над вашим объектом и упрощает тестируемость (PHPUnit сильно зависит от Reflection)

Переработан
источник