2012-10-19 12 views
6

चलें कहते हैं कि मैं इस तरह विधि के साथ वर्ग को परिभाषित:किसी भी क्रम में PHP फ़ंक्शन या विधि तर्क का उपयोग कैसे करें?

class Test { 
    public function doStuff($a, $b, $c) { 
    // -- Do stuff -- 
    } 
} 

यह इस पद्धति का उपयोग करना संभव है लेकिन भिन्न क्रम में तर्क के साथ, इस तरह:

$test = new Test(); 
$test->doStuff($b, $c, $a); 

वे एक ही नाम है, लेकिन सिर्फ अलग आदेश।

मैं देख रहा हूँ Symfony2 अपने डिस्पैचर के साथ यह कर सकते हैं, तो आप आप चाहते हैं किसी भी क्रम में तर्कों का उपयोग कर सकते हैं। लिंक: Symfony2 controller can do it

सवाल यह है कि यह काम कैसे करें? Symfony2 उचित क्रिया नियंत्रक कैसे आ सकता है, जो आपके द्वारा पसंद किए गए किसी भी क्रम में तर्क स्वीकार कर सकता है?

संपादित करें: मैं सरणियों का उपयोग नहीं कर सकते हैं, और मुझे लगता है कि php नामित तर्क का उपयोग नहीं करता पता है। लेकिन किसी भी तरह Symfony2 इसे करने के लिए प्रबंधन करते हैं।

+0

संक्षिप्त उत्तर – kalpaitch

+2

@ kalpaitch है - ठीक है, symfony2 ऐसा करता है, इसलिए एक तरीका है। – otporan

+1

यहां दिए गए सुझावों पर नज़र डालें: http://stackoverflow.com/questions/4697705/php-function-overloading –

उत्तर

8

मुझे लगता है कि आप सिम्फनी कह रहे हैं कि आप गलतफहमी कर रहे हैं। आप किसी भी क्रम में नियंत्रक कार्रवाई में तर्क पारित नहीं कर सकते हैं, इसे एक विशिष्ट क्रम में होना चाहिए। वे जो कर रहे हैं वह गतिशील है, हालांकि, यह पता लगा रहा है कि फ़ंक्शन परिभाषा के अंदर आपके रूटिंग पैरामीटर किस क्रम में हैं।

उदाहरण के लिए हम एक मार्ग को परिभाषित:

pattern:  /hello/{first_name}/{last_name} 
defaults:  { _controller: AcmeHelloBundle:Hello:index, color: green } 

मार्ग में, मानकों first_name, last_name, और color नाम हैं।

वे क्या कह रहे हैं, यह कोई फर्क नहीं पड़ता कि क्या आपको कार्रवाई में मापदंडों के लिए इस्तेमाल करते हैं।

निम्न में से

प्रत्येक बराबर हैं:

public function indexAction($first_name, $last_name, $color) {...} 
public function indexAction($color, $last_name, $first_name) {...} 
public function indexAction($last_name, $color, $first_name) {...} 

के बाद से अपने तर्क नाम हैं मार्ग में पैरामीटर के रूप में ही, Symfony का पता लगा लेता क्या बहस के सही क्रम अपनी परिभाषा के आधार पर है।

आप मैन्युअल रूप से कार्रवाई के बाद कॉल करने के लिए थे, तो:

public function indexAction($first_name, $last_name, $color) 

फिर बहस अभी भी $first_name, $last_name, $color के रूप में और किसी भी अन्य क्रम में नहीं में पारित किया जाना चाहिए। एक अलग क्रम का उपयोग करना गलत मानों को तर्कों के साथ जोड़ देगा। सिम्फनी सिर्फ इस बात की परवाह नहीं करता कि आप अपने फ़ंक्शन को किस क्रम में परिभाषित करते हैं क्योंकि यह ऑर्डर निर्धारित करता है क्योंकि आपके रूटिंग पैरामीटर को आपके विधि तर्कों के समान ही नामित किया जाना चाहिए।

उम्मीद है कि भ्रम को साफ़ करता है।

+0

तो वे गतिशील रूप से उस क्रम को कैसे समझते हैं जिसमें तर्क परिभाषा में तर्क प्रकट होते हैं, वैसे भी? मुझे नहीं लगता कि यह प्रोग्रामेटिक रूप से तब तक किया जा सकता है जब तक फ़ाइल को टेक्स्ट और पार्स के रूप में खोला नहीं जाता है। – Mahn

+3

@Mahn वे कुंजी यह है कि फ़ंक्शन पैरामीटर को रूट पैरामीटर के समान ही नामित किया जाना चाहिए। फिर, कक्षा, विधि, और इसके तर्कों पर जानकारी प्राप्त करने के लिए, वे शायद [ReflectionClass] (http://php.net/reflectionclass) का उपयोग करें और फिर [ReflectionMethod] (http://www.php.net/manual /en/class.reflectionmethod.php) तर्क के क्रम प्राप्त करने के लिए कक्षा विधि पर। – drew010

+0

आह यह सही है, यह प्रतिबिंब कक्षाओं के साथ भी किया जा सकता है। – Mahn

2

नहीं, लेकिन आप अलग-अलग ऑर्डर के साथ ओवरलोडेड विधियों को प्राप्त कर सकते हैं। या आप पैरामीटर के बारे में प्रतिबिंब या बुद्धिमान अनुमान लगाने के साथ ऐसा करने का प्रयास कर सकते हैं। मुझे संदेह है कि आप एक सुरुचिपूर्ण समाधान के साथ आ सकते हैं जो सभी कार्यों के लिए काम करेगा।

1

आप चौथा चर $ $ क्यों नहीं जोड़ते हैं, जो फ़ंक्शन में आने वाले क्रम को परिभाषित करता है।

class Test { 
    public function doStuff($d, $a, $b, $c) { 
     $v=explode(',', $d); 
     foreach($v as $key => $value){ 
     switch ($value){ 
      case 'a': 
      $aa = $v[a]; 
      break; 
      case 'b': 
      $bb = $v[b]; 
      break; 
      case 'a': 
      $cc = $v[c]; 
      break; 
      } 
     echo "a is $aa, b is $bb, c is $cc"; //output 
     } 

// -- Do stuff -- 
} 
} 
$d= "b,c,a"; // the order of the variables 
$test = new Test(); 
$test->doStuff($d, $b, $c, $a); 
+0

दिलचस्प विचार। आपका कोड टूटा हुआ बहुत बुरा है। – Zecc

+0

@Zecc, हाँ, क्षमा करें, मैं सिर्फ एक स्केच कोड का परीक्षण करने में सक्षम नहीं था। मुझे पसंद है कि आपने ऊपर क्या किया है, हालांकि। – Sablefoste

+0

धन्यवाद। आपने मुझे प्रेरणा दी। और मेरे पास पूरी तरह से डीबग करने के लिए कुछ खाली समय था :) – Zecc

4

सेबल फोस्टे के विचार ने मुझे प्रेरित किया।

आप क्रम निर्दिष्ट और उसके बाद के लिए एक और पैरामीटर का उपयोग variable variables उपयोग कर सकते हैं:

function test($order, $_a, $_b, $_c){ 
    $order = explode(';', $order); 
    ${$order[0]} = $_a; 
    ${$order[1]} = $_b; 
    ${$order[2]} = $_c; 

    echo "a = $a; b = $b; c = $c<br>"; 
} 


test('a;b;c', 'a', 'b', 'c'); 
test('b;a;c', 'b', 'a', 'c'); 

लेकिन गंभीरता से, तुम क्यों एक सरणी का उपयोग नहीं कर सकते हैं? यह सबसे अच्छा तरीका है।


अद्यतन: मैं इस लिखा था। मैं वास्तव में ऊब गया होगा।

अब मुझे गंदा लगता है।

class FuncCaller{ 

    var $func; 
    var $order_wanted; 
    var $num_args_wanted; 

    function FuncCaller($func, $order){ 
     $this->func = $func; 
     if(is_set($order)){ 
      // First version: receives string declaring parameters 
      // We flip the order_wanted array so it maps name => index 
      $this->order_wanted = array_flip(explode(';', $order)); 
      $this->num_args_wanted = count($this->order_wanted); 
     } else { 
      // Second version: we can do better, using reflection 
      $func_reflection = new ReflectionFunction($this->func); 
      $params = $func_reflection->getParameters(); 

      $this->num_args_wanted = func_reflection->getNumberOfParameters(); 
      $this->order_wanted = []; 

      foreach($params as $idx => $param_reflection){ 
       $this->order_wanted[ $param_reflection->getName() ] = $idx; 
      } 
     } 
    } 


    function call(){ 
     if(func_num_args() <= 1){ 
      // Call without arguments 
      return $this->func(); 
     } 
     else if(func_num_args() == $this->num_args_wanted){ 
      // order argument not present. Assume order is same as func signature 
      $args = func_get_args(); 
      return call_user_func_array($this->func, $args); 
     } 
     else { 
      // @TODO: verify correct arguments were given 
      $args_given = func_get_args(); 
      $order_given = explode(';', array_shift($args_given)); 
      $order_given = array_flip($order_given); // Map name to index 
      $args_for_call = array(); 
      foreach($this->order_wanted as $param_name => $idx){ 
       $idx_given = $order_given[$param_name]; 
       $val = $args_given[ $idx_given ]; 
       $args_for_call[$idx] = $val; 
      } 
      return call_user_func_array($this->func, $args_for_call); 
     } 
    } 

    // This should allow calling the FuncCaller object as a function,   
    // but it wasn't working for me for some reason 
    function __invoke(){ 
     $args = func_get_args(); 
     return call_user_func($this->call, $args); 
    } 
} 


// Let's create a function for testing: 
function test($first, $second, $third){ 
    $first = var_export($first , TRUE); 
    $second = var_export($second, TRUE); 
    $third = var_export($third , TRUE); 
    echo "Called test($first, $second, $third);<br>"; 
} 

// Now we test the first version: order of arguments is specified 
$caller = new FuncCaller(test, '1st;2nd;3rd'); 
$caller->call(1, 2, 3); 
$caller->call('3rd;1st;2nd', 'c', 'a', 'b'); 
$caller->call('2nd;3rd;1st', 'Two', 'Three', 'One'); 
$caller->call('3rd;2nd;1st', 'Go!', 'Get Set...', 'Get Ready...'); 


echo "<br>"; 

// Now we test the second version: order of arguments is acquired by reflection 
// Note we you won't be able to rename arguments this way, as we did above 
$reflection_caller = new FuncCaller(test); 
$reflection_caller->call(1, 2, 3); 
$reflection_caller->call('third;first;second', 'c', 'a', 'b'); 
$reflection_caller->call('second;third;first', 'Two', 'Three', 'One'); 
$reflection_caller->call('third;second;first', 'Go!', 'Get Set...', 'Get Ready...'); 
2

मुझे लगता है कि वे contoller एक्शन फ़ंक्शन की घोषणा का निरीक्षण करने के लिए प्रतिबिंब का उपयोग करते हैं; फिर वे सही क्रम में तर्कों के साथ फ़ंक्शन कॉल करते हैं।

http://www.php.net/manual/en/class.reflectionparameter.php पर एक नज़र डालें। यह एक getName और getPosition है।

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