Tworzenie instancji klasy PHP za pomocą łańcucha

223

Mam dwie klasy class ClassOne { }i class ClassTwo {}. Otrzymuję ciąg, który może być "One"albo "Two".

Zamiast używać długiej switchinstrukcji, takiej jak:

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

Czy istnieje sposób na utworzenie instancji za pomocą ciągu znaków, tj. new Class("Class" . $str);?

Joel
źródło

Odpowiedzi:

484

Tak, możesz!

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

Korzystając z przestrzeni nazw, podaj w pełni kwalifikowaną nazwę :

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

Inne fajne rzeczy, które możesz zrobić w php to:
Zmienne zmienne :

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

I zmienne funkcje i metody.

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

$method = 'doStuff';
$object = new MyClass();
$object->$method(); // calls the MyClass->doStuff() method. 
Bob Fanger
źródło
1
Dzięki za przykłady!
Joel
28
Do Twojej wiadomości, nie możesz częściowo użyć zmiennej. na przykład. $my_obj = Package\$class_name();. Zamiast tego musisz$class_name = "Package\\" . $class_name; $my_obj = new $class_name();
Birla,
14
Przy korzystaniu z przestrzeni nazw należy podać pełną ścieżkę:$className = '\Foo\Bar\MyClass'; $instance = new $className();
Giel Berkers
5
Nie ma łyżki ... tylko php.
Kapitan Hypertext
4
ale jedno pytanie. Metodę opisaną powyżej można wykorzystać do utworzenia nowej instancji klasy. Co jeśli chcę statycznie wywołać metodę istniejącej klasy? Próbowałem następująco: $model = $user_model::find()->All(); gdzie $user_modeljest zmienna zawierająca ciąg klasy o nazwie
Ramesh Pareek
22

Możesz po prostu użyć następującej składni, aby utworzyć nową klasę (jest to przydatne, jeśli tworzysz fabrykę ):

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

Jako (wyjątkowo surowa) przykładowa metoda fabryczna:

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.');
}
John Parker
źródło
1
Nie brakuje Ci kropki między nazwą klasy a rozszerzeniem? require_once($className.'php'); ->require_once($className.'.php');
J Quest
4

Powiedzmy, że ClassOnejest zdefiniowany jako:

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

}

Korzystanie z PHP Reflection;

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

Utwórz nową instancję:

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

Wywołaj metodę:

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

Użyj zmiennej jako metody:

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

//prints "Banana"

Użycie Reflection zamiast zwykłego ciągu do utworzenia obiektu daje lepszą kontrolę nad obiektem i łatwiejszą testowalność (PHPUnit w dużym stopniu opiera się na Reflection)

Przerobiony
źródło