2011-11-05 12 views
10

私は、Googleの結果のページだけでなく、ここでstackoverflowを検索しましたが、私の状況に合った解決策を見つけることができません。私はcall_user_func_arrayを使って動的にオブジェクトを作成するビルドしようとしている関数に最後の障害が1つあります。call_user_func_arrayはコンストラクタに引数を渡します

キャッチ可能な致命的なエラーはObject of class Product could not be converted to stringです。エラーが発生した場合、ログにこれらのうちの5つ(各引数に1つ)があります。キャッチ可能な致命的なエラーが発生する前にPHP Warning: Missing argument 1 for Product::__construct(),

これは、関数のコードです:

public static function SelectAll($class, $table, $sort_field, $sort_order = "ASC") 
{ 
/* First, the function performs a MySQL query using the provided arguments. */ 

$query = "SELECT * FROM " .$table. " ORDER BY " .$sort_field. " " .$sort_order; 
$result = mysql_query($query); 

/* Next, the function dynamically gathers the appropriate number and names of properties. */ 

$num_fields = mysql_num_fields($result); 
for($i=0; $i < ($num_fields); $i++) 
{ 
    $fetch = mysql_fetch_field($result, $i); 
    $properties[$i] = $fetch->name; 
} 

/* Finally, the function produces and returns an array of constructed objects.*/ 

while($row = mysql_fetch_assoc($result)) 
{ 
    for($i=0; $i < ($num_fields); $i++) 
    { 
    $args[$i] = $row[$properties[$i]]; 
    } 
    $array[] = call_user_func_array (new $class, $args); 
} 

return $array; 
} 

、私はcall_user_func_array行をコメントアウトし、これに置き換える場合:

$array[] = new $class($args[0],$args[1],$args[2],$args[3],$args[4]); 

ページが読み込まそれが必要、と移入します私が作るテーブル。実際には私が$args配列をcall_user_func_arrayに実際に使用しようとするまで、すべてが絶対に機能します。

私は行方不明の配列を呼び出すことについていくつか微妙な詳細がありますか? call_user_func_arrayのPHPマニュアルを一度読んだところ、そのページのいくつかの例は、配列を作成して2番目の引数のために呼び出すだけの人に見えていたようでした。私は何が間違っていますか?

答えて

20

あなたはこのよう$classのコンストラクタを呼び出すことはできません。最初のパラメータとして何valid callbackません

call_user_func_array (new $class, $args); 

を。さんがこれを離れて選んでみましょう:

call_user_func_array (new $class, $args); 

は、あなたが見ることができるようにcall_user_func_arrayが行動に出る前に、$classのコンストラクタが既に呼び出されてい

$obj = new $class; 
call_user_func_array ($obj, $args); 

と同じです。それはパラメータがないと、このエラーメッセージを参照してください。それに

Missing argument 1 for Product::__construct() 

次に、$objはObject型です。有効なコールバックは、文字列または配列(または例外的に特別なオブジェクト:Closure)でなければなりませんが、ここでは説明しません。完全性のために名前を付けます。あなたがPHPのエラーメッセージが表示されるので、$objとして

は、オブジェクトではなく、有効なコールバックです:

Object of class Product could not be converted to string. 

PHPはそれを許可していない文字列にオブジェクトを変換しようとします。

このように、オブジェクトはまだ存在しないため、コンストラクタのコールバックを簡単に作成することはできません。おそらくあなたがマニュアルで簡単にそれを見ることができなかった理由です。

コンストラクタは、ここにいくつかの特別な取引を必要とする:あなたは未初期化オブジェクトのクラスのコンストラクタに、可変引数を渡す必要がある場合は、これを行うにはReflectionClassを使用することができます。

$ref = new ReflectionClass($class); 
    $new = $ref->newInstanceArgs($args); 

を参照してくださいReflectionClass::newInstanceArgs

(名前として提案する)ので、それは関数/メソッドを呼び出しますが、オブジェクトを作成するために意図されていない、 call_user_func_array()を使用不可
+0

ありがとう、私は '有効なコールバック'エラーを得ていないし、エラー'call_user_func_array'は、特定のコンストラクタが期待している何らかの理由で、PHPの警告:Product :: __ construct()の引数1がありません。受信する。もちろん、それは私がまだ理解していないものかもしれませんが、それは私がこれまで持っている知識です。 – tuespetre

+0

最初にオブジェクトを 'new $ class'でインスタンス化します。これは、 'call_user_func_array' getが動作する前にコンストラクタがすでに呼び出されていることを意味します。分かりますか?最初に 'new'が来ました。なぜなら、それをパラメータの式として使用してから、関数呼び出しが起こるからです。しかし、新しいものが実行されたため、 '$ class'のコンストラクタはすでに(引数なしで)呼び出されています。そして、PHPはオブジェクトを文字列に変換しようとします。なぜなら、最初のパラメータは文字列または配列を必要とするからです。オブジェクトが文字列へのキャストをサポートしていないため、エラー/警告が表示されます。 – hakre

+0

私は見る!ありがとうございました。私は、引数をコンストラクタに動的に渡す他の方法を検討します。 – tuespetre

2

、使用ReflectionClass

$refClass = new ReflectionClass($class); 
$object = $refClass->newInstanceArgs($args); 

別の(より多くの設計ベース)ソリューションは、静的ファクトリメソッド

class MyClass() { 
    public static function create ($args) { 
    return new self($args[0],$args[1],$args[2],$args[3],$args[4]); 
    } 
} 

と私の目にはその後、ちょうど

$object = $class::create($args); 

である、それはきれいだ、なぜなら少ない魔法とより多くの制御が

+0

あなたは 'Product :: __ construct($ args)'のように '$ args'が引数の配列であるとすることができます。そのような引数配列を使ってすべての関数を呼び出すことはできますか? – tuespetre

+0

私はどこでそのようなことを言ったのですか?もちろん、配列を使ってオブジェクトをインスタンス化することはできますが、その配列はコンストラクタ内の単一の引数として受け取ります。それはあなたが望むもののように見えません – KingCrunch

+0

申し訳ありませんが、私はあなたの投稿を誤解しました。 :) – tuespetre

0

I ReflectionClassが依存ツリーを壊してしまったため、これをシングルトンのファクトリパターンに使用すると、evalの使用は嫌いですが、PHPUnitを使ってシングルトンパターンを使用してシンプルパターンを使用する方法が簡単になりますその注射にクラスメソッドを開こうとすると、あなたが評価するべきデータを知っておいてください!!!!!!!!!あなたはそれがきれいで掃除されていることを確認する必要があります!

abstract class Singleton{ 
    private static $instance=array();//collection of singleton objects instances 
    protected function __construct(){}//to allow call to extended constructor only from dependence tree 
    private function __clone(){}//to disallow duplicate 
    private function __wakeup(){}//comment this if you want to mock the object whith php unit jejeje 

    //AND HERE WE GO!!! 
    public static function getInstance(){   
    $a=get_called_class(); 
    if(!array_key_exists($a, self::$instance)){ 
     if(func_num_args()){ 
      /**HERE IS THE CODE **// 
      $args=func_get_args(); 
      $str='self::$instance[$a]=new $a('; 
      for($i=0;$i<count($args);$i++){ 
       $str.=(($i)?",":"").'$args['.$i.']'; 
      } 
      eval($str.");");//DANGER, BE CAREFULLY...we only use this code to inject MockObjects in testing...to another use you will use a normal method to configure the SingletonObject 
      /*--------------------------*/ 
     }else{ 
      self::$instance[$a]=new $a(); 
     } 

    } 
    return self::$instance[$a];  
} 


} 

そして、それを使用する:

class MyClass extends Singleton{ 
    protected function __construct(MyDependInjection $injection){ 
     //here i use the args like a normal class but the method IS PROTECTED!!! 
    } 
} 

オブジェクトをインスタンス化する:

$myVar= MyClass::getInstance($objetFromClassMyDependInjection); 

それは私がpased引数whithコンストラクタを呼び出します。私は静的メソッドgetInstanceを拡張するのと同じ結果を得ることができるが、チームワークにはこのように使いやすいということを知っている。

関連する問題