2012-01-04 19 views
12

Wiem, że można wywołać funkcję o zmiennej liczbie parametrów z opcją call_user_func_array() znalezioną tutaj ->http://php.net/manual/en/function.call-user-func-array.php. To, co chcę zrobić, jest prawie identyczne, ale zamiast funkcji chcę wywołać klasę PHP ze zmienną liczbą parametrów w jej konstruktorze.Dynamicznie wywołaj klasę ze zmienną liczbą parametrów w konstruktorze

Będzie działać jak poniżej, ale nie będę znać liczby parametrów, więc nie będę wiedział, jak utworzyć instancję klasy.

<?php 
//The class name will be pulled dynamically from another source 
$myClass = '\Some\Dynamically\Generated\Class'; 
//The parameters will also be pulled from another source, for simplicity I 
//have used two parameters. There could be 0, 1, 2, N, ... parameters 
$myParameters = array ('dynamicparam1', 'dynamicparam2'); 
//The instantiated class needs to be called with 0, 1, 2, N, ... parameters 
//not just two parameters. 
$myClassInstance = new $myClass($myParameters[0], $myParameters[1]); 
+0

Twoje pytanie jest trochę niejednoznaczne. Wygląda na to, że mówisz, że nie wiesz teraz, ile argumentów przyjmie konstruktor, ale jest to pewna kwota, która zostanie naprawiona w środowisku wykonawczym i chcesz wywołać ją z poprawnym numerem. Czy to jest poprawne? –

+0

@jubba Tak ... Nazwa klasy, która ma być instancjonowana i zdefiniowane zostaną parametry konstruktora. Wyciągam te informacje z innego źródła.Dla uproszczenia zostawiłem to z tego kodu. Zamierzam skomentować powyższy kod, aby wyjaśnić. – bmarti44

+3

Widziałeś [to pytanie] (http://stackoverflow.com/questions/1569949/instantiating-a-new-php-class-with-one-or-many-arguments)? Odpowiedzi mogą rozwiązać twój problem. –

Odpowiedz

37

można wykonać następujące czynności przy użyciu ReflectionClass

$myClass = '\Some\Dynamically\Generated\a'; 
$myParameters = array ('dynamicparam1', 'dynamicparam2'); 

$reflection = new \ReflectionClass($myClass); 
$myClassInstance = $reflection->newInstanceArgs($myParameters); 

PHP Manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php

Edit:

w PHP 5.6 można to osiągnąć z Argument unpacking.

$myClass = '\Some\Dynamically\Generated\a'; 
$myParameters = ['dynamicparam1', 'dynamicparam2']; 

$myClassInstance = new $myClass(...$myParameters); 
+0

To jest właśnie to, co musiałem użyć. Zastanawiam się tylko, czy użycie ReflectionClass spowolni mój kod. – bmarti44

+2

@ bmarti44 zależy od tego, jak będziesz go używał! Oto dwa linki dotyczące wydajności ReflectionClass http://stackoverflow.com/questions/294582/php-5-reflection-api-perance oraz http://blog.liip.ch/archive/2008/09/18/fotd- reflectionclass-newinstanceargs-args-is-slow.html Jeśli spowolniłoby to wydajność twojego kodu, możesz buforować strukturę klasy. – satrun77

7

zaimplementować to podejście dużo kiedy args funkcyjne> 2, a następnie skończyć z listy Bożego Narodzenia argumentów, które muszą być w określonej kolejności, po prostu przechodzą w tablicy asocjacyjnej. Przekazując tablicę asocjacyjną, mogę sprawdzić potrzebne i opcjonalne argumenty oraz w razie potrzeby obsłużyć brakujące wartości. Coś jak:

class MyClass 
{ 
    protected $requiredArg1; 
    protected $optionalArg1; 

    public function __construct(array $options = array()) 
    { 
     // Check for a necessary arg 
     if (!isset($options['requiredArg1'])) { 
      throw new Exception('Missing requiredArg1'); 
     } 

     // Now I can just localize 
     $requiredArg1 = $options['requiredArg1']; 
     $optionalArg1 = (isset($options['optionalArg1'])) ? $options['optionalArg1'] : null; 

     // Now that you have localized args, do what you want 
     $this->requiredArg1 = $requiredArg1; 
     $this->optionalArg1 = $optionalArg1;    
    } 
} 

// Example call 
$class = 'MyClass'; 
$array = array('requiredArg1' => 'Foo!', 'optionalArg1' => 'Bar!'); 

$instance = new $class($array); 

var_dump($instance->getRequiredArg1()); 
var_dump($instance->getOptionalArg1()); 

Bardzo polecam używanie tablicy asocjacyjnej, jednak możliwe jest użycie tablicy 0-index. Będziesz musiał być bardzo ostrożny przy konstruowaniu tablicy i uwzględniać indeksy, które mają znaczenie, w przeciwnym razie przekażesz tablicę z argumentami offsetu i spustoszenia wraku z twoją funkcją.

+0

Chciałbym użyć tej metody, ale. . . Jedna z używanych klas wymaga dwóch argumentów i nie została napisana przeze mnie. . . Więc muszę iść z ReflectionClass. Dziękuję za tę metodę, ale na pewno wykorzystamy ją we wszystkich nowych klasach. – bmarti44

+0

Używam również tej metody, ale używam tylko tablicy '$ options' dla ściśle _optional_ parametrów i zezwalam na _kompilator_ na brak wymaganych argumentów w wywołaniu metody. – MrWhite

0

Możesz to zrobić, używając func_get_args().

class my_class { 
    function __construct($first = NULL) { 
     $params = func_get_args(); 
     if(is_array($first)) 
      $params = $first; 
     // the $params array will contain the 
     // arguments passed to the child function 
     foreach($params as $p) 
      echo "Param: $p\n"; 
    } 
} 
function my_function() { 
    $instance = new my_class(func_get_args()); 
} 

echo "you can still create my_class instances like normal:"; 
$instance = new my_class("one", "two", "three"); 
echo "\n\n\n"; 
echo "but also through my_function:"; 
my_function("one", "two", "three"); 

Zasadniczo, można po prostu przejść wynik func_get_args do konstruktora klasy, i niech się zdecydować, czy jest ona wywoływana z tablicy argumentów z tej funkcji, czy też jest on nazywany normalnie.

Ten kod wysyła

you can still create my_class instances like normal: 
Param: one 
Param: two 
Param: three 

but also through my_function: 
Param: one 
Param: two 
Param: three 

nadzieję, że pomoże.

0

Znalazłem tutaj

Is there a call_user_func() equivalent to create a new class instance?

przykładzie:

function createInstance($className, array $arguments = array()) 
{ 
    if(class_exists($className)) { 
     return call_user_func_array(array(
      new ReflectionClass($className), 'newInstance'), 
      $arguments); 
    } 
    return false; 
} 

Ale może ktoś mi powiedzieć, czy jest to przykład na zajęcia z chronionymi konstruktorów?

Powiązane problemy