2011-11-05 11 views
10

पर तर्क पारित करने के लिए मैंने Google परिणामों के कई पेजों के साथ-साथ यहां स्टैक ओवरफ्लो पर भी खोज की है लेकिन मेरी स्थिति में फिट होने वाला कोई समाधान नहीं मिल रहा है। मेरे पास उस समारोह में एक आखिरी झगड़ा है जो मैं बनाने की कोशिश कर रहा हूं, जो गतिशील रूप से वस्तुओं को बनाने के लिए call_user_func_array का उपयोग करता है।call_user_func_array एक कन्स्ट्रक्टर

मुझे प्राप्त होने वाली आकर्षक घातक त्रुटि Object of class Product could not be converted to string है। जब त्रुटि होती है, लॉग में मुझे इनमें से पांच मिलते हैं (प्रत्येक तर्क के लिए एक): PHP Warning: Missing argument 1 for Product::__construct(), पकड़ने योग्य घातक त्रुटि से पहले। अगर मैं call_user_func_array लाइन बाहर टिप्पणी और इस के साथ बदलने, अब

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

:

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

एकदम सही ढंग से पेज लोड होता है और भरता है

इस समारोह का कोड है जिस टेबल को मैं बना रहा हूं। तो जब तक मैं वास्तव में सरणी call_user_func_array के भीतर उपयोग करने का प्रयास नहीं करता तब तक सबकुछ बिल्कुल कार्यात्मक होता है।

क्या उस सरणी को कॉल करने के बारे में कुछ सूक्ष्म विवरण है जो मुझे याद आ रही है? मैंने एक बार call_user_func_array के लिए PHP मैनुअल पढ़ा, और फिर कुछ, और उस पृष्ठ पर उदाहरण लोगों को सिर्फ एक सरणी बनाने और दूसरे तर्क के लिए बुलाते हुए लग रहा था। मुझ से ऐसी कौनसी गलती हो जाएगी?

उत्तर

20

आप इस तरह $class के निर्माता फोन नहीं कर सकते हैं:

call_user_func_array (new $class, $args); 

कि पहले पैरामीटर के रूप में कोई valid callback है। चलो इस के अलावा चुनाव करने दें:

call_user_func_array (new $class, $args); 

आप देख सकते हैं, $class के निर्माता पहले से ही बुलाया गया है से पहले call_user_func_array कार्रवाई में आता है के रूप

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

एक ही है। यह कोई पैरामीटर के रूप में, आप यह त्रुटि संदेश दिखाई:

Missing argument 1 for Product::__construct() 

कि के आगे, $obj प्रकार वस्तु की है। एक वैध कॉलबैक या तो एक स्ट्रिंग या सरणी होनी चाहिए (या असाधारण रूप से एक बहुत ही विशेष वस्तु: Closure, लेकिन यह यहां चर्चा से बाहर है, मैं केवल इसे पूर्णता के लिए नामित करता हूं)।

$obj के रूप में एक वस्तु और एक मान्य कॉलबैक है, इसलिए आप PHP त्रुटि संदेश दिखाई:

Object of class Product could not be converted to string. 

पीएचपी स्ट्रिंग है, जो यह अनुमति नहीं है करने के लिए वस्तु कन्वर्ट करने के लिए कोशिश करता है।

तो जैसा कि आप देख सकते हैं, आप आसानी से एक कन्स्ट्रक्टर के लिए कॉलबैक नहीं बना सकते हैं, क्योंकि ऑब्जेक्ट अभी तक मौजूद नहीं है। शायद यही कारण है कि आप आसानी से मैन्युअल में इसे देखने में सक्षम नहीं थे।

कंस्ट्रक्टर्स यहाँ कुछ विशेष निपटने की जरूरत है: आप एक नहीं अभी तक प्रारंभ वस्तु के एक वर्ग के निर्माता के लिए चर तर्क पारित करने के लिए की जरूरत है, तो आप ऐसा करने के लिए ReflectionClass उपयोग कर सकते हैं:

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

देखें ReflectionClass::newInstanceArgs

+0

आपके उत्तर के लिए धन्यवाद, हालांकि, मुझे 'कोई वैध कॉलबैक' त्रुटि नहीं मिल रही है, और त्रुटि लॉग प्रतीत होता है कि 'call_user_func_array' सफलतापूर्वक निर्माण को कॉल करता है, क्योंकि यह मुझे' PHP चेतावनी देता है: विशेष कन्स्ट्रक्टर की अपेक्षा की जा रही पांच तर्कों में से प्रत्येक के लिए उत्पाद :: __ निर्माण() 'के लिए गुम तर्क 1) लेकिन किसी कारण से नहीं प्राप्त करते हुए। बेशक, यह ऐसा कुछ हो सकता है जिसे मैं अभी तक समझ नहीं पा रहा हूं, लेकिन वह ज्ञान है जो मेरे पास है। – tuespetre

+0

आप पहले ऑब्जेक्ट को 'नई $ कक्षा' के साथ तुरंत चालू करते हैं। इसका मतलब है कि कन्स्ट्रक्टर को पहले से ही 'call_user_func_array' कार्रवाई में आने से पहले बुलाया गया है। आप समझ सकते हैं? सबसे पहले 'नया' आता है क्योंकि आप इसे पैरामीटर में अभिव्यक्ति के रूप में उपयोग करते हैं, फिर फ़ंक्शन कॉल होता है। लेकिन नए निष्पादित होने के कारण, '$ वर्ग' के निर्माता को पहले से ही बुलाया गया है (बिना तर्क के)। और फिर PHP ऑब्जेक्ट को स्ट्रिंग में बदलने की कोशिश करता है क्योंकि पहला पैरामीटर स्ट्रिंग या सरणी की अपेक्षा करता है। चूंकि आपका ऑब्जेक्ट तारों को कास्टिंग का समर्थन नहीं करता है, इसलिए आपको त्रुटि/चेतावनी मिलती है। – hakre

+0

मैं देखता हूँ! धन्यवाद। मैं एक निर्माता को गतिशील रूप से तर्क पारित करने के अन्य तरीकों को देखूंगा। – tuespetre

2

, call_user_func_array() का उपयोग कर, क्योंकि (नाम के रूप में सुझाव है) यह कहता कार्य/तरीकों, लेकिन वस्तुओं को बनाने के लिए नहीं है संभव नहीं है, का प्रयोग करें 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

आपका मतलब है कि आप कॉल कर सकते हैं, उदाहरण के लिए 'उत्पाद :: __ निर्माण ($ args)' जहां '$ args' तर्कों की एक सरणी है? क्या सभी कार्यों को इस तरह एक तर्क सरणी का उपयोग करके बुलाया जा सकता है? – tuespetre

+0

मैंने ऐसा कुछ कहां कहा?! बेशक आप सरणी के साथ वस्तुओं को instanciate कर सकते हैं, लेकिन फिर आप उस सरणी को कन्स्ट्रक्टर में एकल तर्क के रूप में प्राप्त करेंगे।ऐसा लगता है कि आप – KingCrunch

+0

क्या चाहते हैं क्षमा करें, मैंने आपकी पोस्ट को गलत तरीके से पढ़ा है। :) – tuespetre

0

मैं में है सिंगलटन फैक्ट्री पैटर्न के लिए इसका उपयोग करें, क्योंकि रिफ्लेक्शन क्लास निर्भरता पेड़ को ब्रोक करता है, मुझे eval के उपयोग से नफरत है, लेकिन यह एकमात्र तरीका है जिसे मैं सिंगलटन पैटर्न के उपयोग को सरलीकृत करने के लिए ढूंढता हूं, ताकि PHPUnit whi के साथ mockObjects को इंजेक्ट किया जा सके। उस इंजेक्शन के लिए कक्षा विधियों को खोलने के लिए, सावधानी बरतें जब आप समारोह को निकालने के लिए क्या चाहते हैं !!!!!!!! आपको यह सुनिश्चित करना होगा कि साफ और फ़िल्टर किया गया है !!!

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


} 

और वह उपयोग करने के लिए:

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

यह args मैं पारित whith निर्माता कहता है:

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

वस्तु instanciate करने के लिए। मुझे पता है कि मैं स्थिर विधि को विस्तारित करने का एक ही परिणाम प्राप्त कर सकता हूं लेकिन इस तरह का उपयोग करने के लिए टीमवर्किंग को और अधिक आसान बनाने के लिए

संबंधित मुद्दे