instanciar uma classe a partir de uma variável em PHP?

146

Eu sei que essa pergunta parece bastante vaga, então vou deixar mais claro com um exemplo:

$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');

É isso que eu quero fazer. Como você faria? É claro que eu poderia usar eval () assim:

$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');

Mas prefiro ficar longe de eval (). Existe alguma maneira de fazer isso sem eval ()?

Pim Jager
fonte

Respostas:

213

Coloque o nome da classe em uma variável primeiro:

$classname=$var.'Class';

$bar=new $classname("xyz");

Geralmente, esse é o tipo de coisa que você verá envolto em um padrão de fábrica.

Consulte Namespaces e recursos de linguagem dinâmica para obter mais detalhes.

Paul Dixon
fonte
2
É assim que eu faço. Observe que nas classes você pode usar pai e auto.
Ross
1
Em uma nota semelhante, você também pode fazer $ var = 'Name'; $ obj -> {'get'. $ var} ();
Mario
1
Bom ponto, no entanto, que só funciona para chamadas de método e não construtores
Paul Dixon
12
Se você trabalha com espaço para nome, coloque o espaço para nome atual na cadeia de caracteres:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey
@bastey - mas por quê? Eu só passei muito tempo em descobrir, por que isso não iria funcionar sem o namespace que precede o nome da classe ...
jkulak
72

Se você usar namespaces

Nas minhas próprias descobertas, acho bom mencionar que você (pelo que sei) deve declarar o caminho completo do espaço para nome de uma classe.

MyClass.php

namespace com\company\lib;
class MyClass {
}

index.php

namespace com\company\lib;

//Works fine
$i = new MyClass();

$cname = 'MyClass';

//Errors
//$i = new $cname;

//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;
csga5000
fonte
6
A única solução que funciona quando é necessário criar com espaço para nome é a sua. Obrigado por compartilhar!
Tiago Gouvêa
Mas isso é estranho: por que não usar o espaço de nome declarado?
21818 Yisrael Dov
@YisraelDov Sim, é definitivamente contra-intuitivo. Mas, por qualquer motivo, ele se comporta estranhamente nesse contexto. Obrigado php
csga5000
@YisraelDov Acho que é porque, nesse caso, instanciar uma classe de outro espaço para nome seria uma enorme dor de cabeça. Considere também que variáveis ​​podem ser passadas. Quando o nome da classe é escrito como texto em um arquivo php, quem o escreve sabe exatamente em que espaço para nome está escrito. Mas quando uma variável é passada entre as funções, seria um pesadelo acompanhá-lo. Além disso, se você usar get_class (), retornará o nome da classe FQ, para que possa ser armazenado em uma variável imediatamente e usado em qualquer lugar. Se dependesse do espaço para nome do arquivo, não funcionaria muito bem.
sbnc.eu
61

Como passar parâmetros dinâmicos do construtor também

Se você deseja passar parâmetros dinâmicos do construtor para a classe, pode usar este código:

$reflectionClass = new ReflectionClass($className);

$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);

Mais informações sobre classes dinâmicas e parâmetros

PHP> = 5.6

No PHP 5.6, você pode simplificar isso ainda mais usando o Argument Unpacking :

// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);

Agradecemos a DisgruntledGoat por apontar isso.

gripe
fonte
7
No PHP 5.6, você deve ser capaz de usar o desempacotamento de argumentos:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
zalew
fonte
Não, não é um bom exemplo. Só funciona se tudo estiver no mesmo arquivo php.
Fralbo
2
2ndGAB deve remover este comentário. O carregamento automático não tem nada a ver com esta pergunta.
22617 Jim Maguire
-1

Eu recomendaria os métodos call_user_func()ou call_user_func_arrayphp. Você pode vê-los aqui ( call_user_func_array , call_user_func ).

exemplo

class Foo {
static public function test() {
    print "Hello world!\n";
}
}

 call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
 //or
 call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array

Se você tiver argumentos que está passando para o método, use a call_user_func_array()função

exemplo.

class foo {
function bar($arg, $arg2) {
    echo __METHOD__, " got $arg and $arg2\n";
}
}

// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));
pickman murimi
fonte
3
Esta resposta não se aplica à pergunta. O OP está perguntando como INSTALAR uma classe (acionando o método da classe __construct dinamicamente) a partir de uma string variável e recuperando o CLASS OBJECT em uma nova variável - seu conselho retornará o VALUE do class-> method ([]) que você ' re-chamando, não o objeto de classe, portanto não se aplica a este caso. Veja o valor de retorno php.net/manual/en/function.call-user-func-array.php
ChrisN