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 ()?

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.


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;

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.


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

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.