PHP फ़ंक्शन ओवरलोडिंग


195

C ++ पृष्ठभूमि से आ रहा है;)
मैं PHP कार्यों को कैसे अधिभारित कर सकता हूं?

एक फ़ंक्शन परिभाषा अगर कोई तर्क है, और दूसरा अगर कोई तर्क नहीं है? क्या यह PHP में संभव है? या क्या मुझे यह जांचने के लिए उपयोग करना चाहिए कि क्या $ _GET और POST से कोई पैरामीटर पारित हुआ है ?? और उन्हें संबंधित?


1
आप केवल क्लास के तरीकों को ओवरलोड कर सकते हैं, लेकिन फ़ंक्शंस नहीं। Php.net/manual/en/language.oop5.overloading.php पर
Spechal

1
आप एक फ़ंक्शन बना सकते हैं जो तर्कों की संख्या को स्पष्ट रूप से जांचता है और उनमें से एक पूर्वनिर्धारित सेट से दूसरे फ़ंक्शन को निष्पादित करता है। होवर आप अपने समाधान को बेहतर ढंग से डिजाइन करेंगे, या उन कक्षाओं का उपयोग करेंगे जो आपके इंटरफ़ेस को लागू करते हैं
kolypto

2
जैसा कि php.net/manual/en/language.oop5.overloading.php कहता है, PHP की ओवरलोडिंग की परिभाषा ओओपी की विशिष्ट भाषा से अलग है। वे सिर्फ जादू के तरीकों का उल्लेख करते हैं जो एक्स के आधार पर गुणों और कार्यों के गतिशील मार्ग के लिए अनुमति देते हैं।
एडविन डेनियल

भविष्य के पाठकों के लिए: @Spechal जिस शब्द का उल्लेख कर रहा है, वह शब्द के लिए एक अलग अर्थ है overloading, जो प्रश्न में पूछा जा रहा है। (अधिक विवरण के लिए स्वीकृत उत्तर देखें।)
टूलमेकरसैट

2
PHP 7 के बाद से कुछ भी बदला? : ओ
नफ़्फ़ल

जवाबों:


218

आप PHP कार्यों को अधिभार नहीं दे सकते। फ़ंक्शन हस्ताक्षर केवल उनके नामों पर आधारित होते हैं और उनमें तर्क सूची शामिल नहीं होती है, इसलिए आपके पास एक ही नाम के दो कार्य नहीं हो सकते हैं। PHP में कई अन्य भाषाओं की तुलना में क्लास विधि ओवरलोडिंग अलग है। PHP एक ही शब्द का उपयोग करता है लेकिन यह एक अलग पैटर्न का वर्णन करता है।

हालाँकि, आप एक वैरिएबल फ़ंक्शन की घोषणा कर सकते हैं जो एक चर संख्या में तर्क लेता है। आप का प्रयोग करेंगे func_num_args()और func_get_arg()तर्क पारित कर पाने के लिए, और उन्हें सामान्य रूप से उपयोग करें।

उदाहरण के लिए:

function myFunc() {
    for ($i = 0; $i < func_num_args(); $i++) {
        printf("Argument %d: %s\n", $i, func_get_arg($i));
    }
}

/*
Argument 0: a
Argument 1: 2
Argument 2: 3.5
*/
myFunc('a', 2, 3.5);

8
हो सकता है कि मैं C ++ का विकास बहुत अधिक कर रहा हूं, लेकिन मैं एक सुझाव देना चाहूंगा कि यह फ़ंक्शन मापदंडों में किया जा रहा है myFunc(/*...*/)
doug65536

4
@ doug65536, PHP 5.6+ हमारे महान राहत के लिए सिंटैक्स टोकन के रूप में "..." का समर्थन करेगा । ;)
एसजे।

या आदिल का उत्तर देखें , जो C ++ के ओवरलोडिंग के करीब है - जितना करीब संभव है, php जैसी शिष्ट भाषा में। यह php 7 में और भी उपयुक्त है, जैसा कि आप मापदंडों के लिए टाइप संकेत प्रदान कर सकते हैं, यदि वे आपके सभी अधिभार में एक ही प्रकार हैं।
टूलमेकरसैट

78

PHP पारंपरिक तरीके को ओवरलोडिंग का समर्थन नहीं करता है, हालांकि एक तरीका जिससे आप प्राप्त कर सकते हैं कि आप क्या चाहते हैं, __callजादू का उपयोग करना होगा :

class MyClass {
    public function __call($name, $args) {

        switch ($name) {
            case 'funcOne':
                switch (count($args)) {
                    case 1:
                        return call_user_func_array(array($this, 'funcOneWithOneArg'), $args);
                    case 3:
                        return call_user_func_array(array($this, 'funcOneWithThreeArgs'), $args);
                 }
            case 'anotherFunc':
                switch (count($args)) {
                    case 0:
                        return $this->anotherFuncWithNoArgs();
                    case 5:
                        return call_user_func_array(array($this, 'anotherFuncWithMoreArgs'), $args);
                }
        }
    }

    protected function funcOneWithOneArg($a) {

    }

    protected function funcOneWithThreeArgs($a, $b, $c) {

    }

    protected function anotherFuncWithNoArgs() {

    }

    protected function anotherFuncWithMoreArgs($a, $b, $c, $d, $e) {

    }

}

20
मैंने पहले इसका उपयोग नहीं देखा है __call()। सुंदर रचनात्मक (यदि थोड़ी सी क्रिया)! +1
BoltClock


2
वास्तव में, इस बात से सहमत नहीं हो सकते, और इस सुझाव के साथ पुन: प्रयास करना चाहिए। एक के लिए, __call () का यह उपयोग एक प्रतिमान है। दूसरे, यह सही दृश्यता वाले वर्ग विधियों के लिए PHP में ओवरलोडिंग करना संभव है। हालाँकि, आप नहीं कर सकते हैं - सादे-जेन फ़ंक्शन को अधिभारित करें।
Oddman

1
क्या आप बता सकते हैं कि आपको क्यों लगता है कि __call () एक विरोधी पैटर्न है? PHP मेथड ओवरलोडिंग वह नहीं है जो ओपी देख रहा है - वे एक ही नाम के साथ एक से अधिक विधि हस्ताक्षर करने की क्षमता चाहते हैं, लेकिन अलग इनपुट / आउटपुट: en.wikipedia.org/wiki/Function_overloading
Stephen

20
__Call () का उपयोग करने की कोई आवश्यकता नहीं है। इसके बजाय एक विधि घोषित करें जिसका नाम आप चाहते हैं, सूचीबद्ध किए गए मापदंडों के बिना, और उचित निजी कार्यान्वयन को भेजने के लिए उस पद्धति के भीतर func_get_args () का उपयोग करें।
फैंटास्टिकजैमीबर्न

30

एक फंक्शन को ओवर लोड करने के लिए, बस पैरामीटर को डिफ़ॉल्ट रूप से शून्य के रूप में पास करें,

class ParentClass
{
   function mymethod($arg1 = null, $arg2 = null, $arg3 = null)  
     {  
        if( $arg1 == null && $arg2 == null && $arg3 == null ){ 
           return 'function has got zero parameters <br />';
        }
        else
        {
           $str = '';
           if( $arg1 != null ) 
              $str .= "arg1 = ".$arg1." <br />";

           if( $arg2 != null ) 
              $str .= "arg2 = ".$arg2." <br />";

           if( $arg3 != null ) 
              $str .= "arg3 = ".$arg3." <br />";

           return $str;
         }
     }
}

// and call it in order given below ...

 $obj = new ParentClass;

 echo '<br />$obj->mymethod()<br />';
 echo $obj->mymethod();

 echo '<br />$obj->mymethod(null,"test") <br />';
 echo $obj->mymethod(null,'test');

 echo '<br /> $obj->mymethod("test","test","test")<br />';
 echo $obj->mymethod('test','test','test');

4
मैं फ़ंक्शन ओवरलोडिंग के रूप में डिफ़ॉल्ट पैरामीटर पर विचार नहीं करता हूं। फ़ंक्शन [या विधि] ओवरलोडिंग का तर्क पारित किए गए प्रकार के आधार पर एक अलग कार्यान्वयन को कॉल करने के साथ अधिक है। डिफ़ॉल्ट मापदंडों का उपयोग केवल आपको कम मापदंडों की सुविधा के साथ एक ही कार्यान्वयन को कॉल करने की अनुमति देता है।
स्केलेबल

1
हां, आप इसे टाइप के आधार पर भी जोड़-तोड़ कर सकते हैं, लेकिन अगर आप जानते हैं कि php शिथिल टाइप की भाषा जानते हैं और इससे निपटने के लिए उससे निपटने की आवश्यकता होती है।
आदिल अब्बासी

1
मैं इस उत्तर को स्वीकृत के रूप में पसंद करता हूं, क्योंकि यह स्पष्ट करता है कि न्यूनतम और अधिकतम संख्या क्या होनी चाहिए। (आवश्यक पैरामीटरों के लिए एक डिफ़ॉल्ट मान प्रदान न करें।) @ स्केलेबल - मैं आदिल से सहमत हूं कि, चूंकि php शिथिल टाइप है, यह प्रभावी रूप से सभी overloadफ़ंक्शन के लिए php में इसका मतलब हो सकता है - फिर भी, आप एक उपयोगी बिंदु बनाते हैं पाठकों को इसके बारे में पता होना चाहिए।
टूलमेकरसैट १ '

11

यह कुछ के लिए हैकिंग हो सकता है, लेकिन मैंने इस तरह से सीखा कि कैसे Cakephp कुछ कार्य करता है और इसे अनुकूलित किया है क्योंकि मुझे लचीलापन पसंद है

विचार यह है कि आपके पास विभिन्न प्रकार के तर्क, सरणियां, वस्तुएं आदि हैं, फिर आप पता लगाते हैं कि आप क्या पारित किए गए थे और वहां से चले गए

function($arg1, $lastname) {
    if(is_array($arg1)){
        $lastname = $arg1['lastname'];
        $firstname = $arg1['firstname'];
    } else {
        $firstname = $arg1;
    }
    ...
}

1
नहीं मैं इसे हैकिश के रूप में नहीं देखता, PHP अपने कई अंतर्निहित कार्यों के लिए ऐसा करता है।
BoltClock

क्योंकि php शिथिल टाइप का होता है, ठीक यही स्थिति इस स्थिति को संभालने वाली होनी चाहिए । Php में इसकी "आवश्यक हैकिशनेस" है।
टूलमेकरसैट

11
<?php   
/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.8
 * create on : 2017-09-17
 * updated on : 2020-01-12
 *****************************/

#> 1. Include Overloadable class

class Overloadable
{
    static function call($obj, $method, $params=null) {
        $class = get_class($obj);
        // Get real method name
        $suffix_method_name = $method.self::getMethodSuffix($method, $params);

        if (method_exists($obj, $suffix_method_name)) {
            // Call method
            return call_user_func_array(array($obj, $suffix_method_name), $params);
        }else{
            throw new Exception('Tried to call unknown method '.$class.'::'.$suffix_method_name);
        }
    }

    static function getMethodSuffix($method, $params_ary=array()) {
        $c = '__';
        if(is_array($params_ary)){
            foreach($params_ary as $i=>$param){
                // Adding special characters to the end of method name 
                switch(gettype($param)){
                    case 'array':       $c .= 'a'; break;
                    case 'boolean':     $c .= 'b'; break;
                    case 'double':      $c .= 'd'; break;
                    case 'integer':     $c .= 'i'; break;
                    case 'NULL':        $c .= 'n'; break;
                    case 'object':
                        // Support closure parameter
                        if($param instanceof Closure ){
                            $c .= 'c';
                        }else{
                            $c .= 'o'; 
                        }
                    break;
                    case 'resource':    $c .= 'r'; break;
                    case 'string':      $c .= 's'; break;
                    case 'unknown type':$c .= 'u'; break;
                }
            }
        }
        return $c;
    }
    // Get a reference variable by name
    static function &refAccess($var_name) {
        $r =& $GLOBALS["$var_name"]; 
        return $r;
    }
}
//----------------------------------------------------------
#> 2. create new class
//----------------------------------------------------------

class test 
{
    private $name = 'test-1';

    #> 3. Add __call 'magic method' to your class

    // Call Overloadable class 
    // you must copy this method in your class to activate overloading
    function __call($method, $args) {
        return Overloadable::call($this, $method, $args);
    }

    #> 4. Add your methods with __ and arg type as one letter ie:(__i, __s, __is) and so on.
    #> methodname__i = methodname($integer)
    #> methodname__s = methodname($string)
    #> methodname__is = methodname($integer, $string)

    // func(void)
    function func__() {
        pre('func(void)', __function__);
    }
    // func(integer)
    function func__i($int) {
        pre('func(integer '.$int.')', __function__);
    }
    // func(string)
    function func__s($string) {
        pre('func(string '.$string.')', __function__);
    }    
    // func(string, object)
    function func__so($string, $object) {
        pre('func(string '.$string.', '.print_r($object, 1).')', __function__);
        //pre($object, 'Object: ');
    }
    // func(closure)
    function func__c(Closure $callback) {

        pre("func(".
            print_r(
                array( $callback, $callback($this->name) ), 
                1
            ).");", __function__.'(Closure)'
        );

    }   
    // anotherFunction(array)
    function anotherFunction__a($array) {
        pre('anotherFunction('.print_r($array, 1).')', __function__);
        $array[0]++;        // change the reference value
        $array['val']++;    // change the reference value
    }
    // anotherFunction(string)
    function anotherFunction__s($key) {
        pre('anotherFunction(string '.$key.')', __function__);
        // Get a reference
        $a2 =& Overloadable::refAccess($key); // $a2 =& $GLOBALS['val'];
        $a2 *= 3;   // change the reference value
    }

}

//----------------------------------------------------------
// Some data to work with:
$val  = 10;
class obj {
    private $x=10;
}

//----------------------------------------------------------
#> 5. create your object

// Start
$t = new test;

#> 6. Call your method

// Call first method with no args:
$t->func(); 
// Output: func(void)

$t->func($val);
// Output: func(integer 10)

$t->func("hello");
// Output: func(string hello)

$t->func("str", new obj());
/* Output: 
func(string str, obj Object
(
    [x:obj:private] => 10
)
)
*/

// call method with closure function
$t->func(function($n){
    return strtoupper($n);
});

/* Output:
func(Array
(
    [0] => Closure Object
        (
            [parameter] => Array
                (
                    [$n] => 
                )

        )

    [1] => TEST-1
)
);
*/

## Passing by Reference:

echo '<br><br>$val='.$val;
// Output: $val=10

$t->anotherFunction(array(&$val, 'val'=>&$val));
/* Output:
anotherFunction(Array
(
    [0] => 10
    [val] => 10
)
)
*/

echo 'Result: $val='.$val;
// Output: $val=12

$t->anotherFunction('val');
// Output: anotherFunction(string val)

echo 'Result: $val='.$val;
// Output: $val=36







// Helper function
//----------------------------------------------------------
function pre($mixed, $title=null){
    $output = "<fieldset>";
    $output .= $title ? "<legend><h2>$title</h2></legend>" : "";
    $output .= '<pre>'. print_r($mixed, 1). '</pre>';
    $output .= "</fieldset>";
    echo $output;
}
//----------------------------------------------------------

4
क्या आप इस वर्ग का उपयोग करने के लिए कुछ स्पष्टीकरण जोड़ सकते हैं?
जस्टस रोमीजन

1- नई कक्षा बनाएं 2- अधिभार का विस्तार। 3- funcname_ () => no args या like funcname_s ($ s) => string arg </ li> जैसे फ़ंक्शंस बनाएं
Hisham Dalal

1
यह बहुत अच्छा समाधान है। आप $ o = नया $ obj () क्यों करते हैं? मैंने इसे अभी तक आज़माया नहीं है, हालाँकि मुझे लगता है कि यह $ $ = = $ होना चाहिए?
over_optimistic

इस महत्वपूर्ण सूचना के लिए धन्यवाद, और मैं बैकस्लैश का उपयोग करूंगा, लेकिन यह बैकस्लैश के साथ और बिना काम कर रहा है! - मैं एक स्थानीय सर्वर के रूप में phpEazy का उपयोग करता हूं।
हिशम दलाल


3

पीएचपी 5.6 में आप उपयोग कर सकते हैं सूचक ऑपरेटर ... पिछले पैरामीटर के रूप में और के साथ भाग कर func_get_args()और func_num_args():

function example(...$args)
{
   count($args); // Equivalent to func_num_args()
}

example(1, 2);
example(1, 2, 3, 4, 5, 6, 7);

आप इसका उपयोग तर्कों को अनपैक करने के लिए भी कर सकते हैं:

$args[] = 1;
$args[] = 2;
$args[] = 3;
example(...$args);

के बराबर है:

example(1, 2, 3);

1
<?php

    class abs
    {
        public function volume($arg1=null, $arg2=null, $arg3=null)
        {   
            if($arg1 == null && $arg2 == null && $arg3 == null)
        {
            echo "function has no arguments. <br>";
        }

        else if($arg1 != null && $arg2 != null && $arg3 != null)
            {
            $volume=$arg1*$arg2*$arg3;
            echo "volume of a cuboid ".$volume ."<br>";
            }
            else if($arg1 != null && $arg2 != null)
            {
            $area=$arg1*$arg2;
            echo "area of square  = " .$area ."<br>";
            }
            else if($arg1 != null)
            {
            $volume=$arg1*$arg1*$arg1; 
            echo "volume of a cube = ".$volume ."<br>";
            }


        }


    }

    $obj=new abs();
    echo "For no arguments. <br>";
    $obj->volume();
    echo "For one arguments. <br>";
    $obj->volume(3);
    echo "For two arguments. <br>";
    $obj->volume(3,4);
    echo "For three arguments. <br>";
    $obj->volume(3,4,5);
    ?>

प्रश्न को संपादित करने और स्वरूपण का उपयोग करने का प्रयास करें। यह आपके उत्तर को अधिक पठनीय बना देगा और अधिक उपयोगकर्ताओं को आकर्षित करेगा।
कशिश अरोड़ा


0

PHP अब ओवरलोडिंग का समर्थन नहीं करता है। आशा है कि इसे अन्य प्रोग्रामिंग भाषाओं की तरह अन्य संस्करणों में भी लागू किया जाएगा।

इस लाइब्रेरी को चेकआउट करें, यह आपको क्लोज़र के संदर्भ में PHP ओवरलोडिंग का उपयोग करने की अनुमति देगा। https://github.com/Sahil-Gulati/Overloading


1
यदि आप इस तरह का बयान देने जा रहे हैं, तो वास्तव में उन संस्करणों को शामिल करना चाहिए जिन्हें आप संदर्भित कर रहे हैं, इस तरह से लोग जानते हैं कि आपकी टिप्पणी कितनी पुरानी है जब वे इसे भविष्य की तारीख में देखते हैं
माइक

0

अफसोस की बात है कि PHP में कोई अधिभार नहीं है क्योंकि यह C # में किया जाता है। लेकिन मैं एक छोटी सी चाल है। मैं डिफ़ॉल्ट अशक्त मूल्यों के साथ तर्कों की घोषणा करता हूं और उन्हें एक फ़ंक्शन में जांचता हूं। इस तरह मेरा कार्य तर्कों के आधार पर अलग-अलग काम कर सकता है। नीचे सरल उदाहरण है:

public function query($queryString, $class = null) //second arg. is optional
{
    $query = $this->dbLink->prepare($queryString);
    $query->execute();

    //if there is second argument method does different thing
    if (!is_null($class)) { 
        $query->setFetchMode(PDO::FETCH_CLASS, $class);
    }

    return $query->fetchAll();
}

//This loads rows in to array of class
$Result = $this->query($queryString, "SomeClass");
//This loads rows as standard arrays
$Result = $this->query($queryString);

1
एक साल बाद नया लिखने से पहले कृपया सभी मौजूदा उत्तरों को पढ़ें। इस तकनीक को पहले से ही दो बार ऊपर के उत्तर में दिखाया गया था। 2013 में एक बार और 2014 में फिर से।
टूलमेकरसैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.