PHP函数重载

Vam*_*a B 186 php arguments overloading

来自C++背景;)
如何重载PHP函数?

一个函数定义是否有任何参数,另一个函数定义没有参数?在PHP中有可能吗?或者我应该使用if else来检查是否有从$ _GET和POST传递的参数?和他们联系?

Bol*_*ock 211

你不能重载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);
Run Code Online (Sandbox Code Playgroud)

  • 也许我一直在做C++开发太多,但我建议提示这是在函数参数中完成的,比如`myFunc(/*...*/)`. (8认同)
  • @ doug65536,PHP 5.6+将支持["..."作为语法标记](http://www.php.net//manual/en/functions.arguments.php),让我们感到非常欣慰.;) (3认同)

Ste*_*hen 76

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) {

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我之前没见过`__call()`.非常有创意(如果有点冗长)!+1 (19认同)
  • 无需使用__call().而是声明一个具有所需名称的方法,而不列出任何参数,并在该方法中使用func_get_args()来分派到适当的私有实现. (19认同)
  • 实际上,不能同意这一点,并且必须对此建议进行重新训练.首先,使用__call()是一种反模式.其次,可以在PHP中对具有正确可见性的类方法进行重载.但是,你不能超载普通的功能. (2认同)

Adi*_*asi 29

要过载函数,只需将参数默认传递为null,

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');
Run Code Online (Sandbox Code Playgroud)

  • 我不认为默认参数是函数重载.函数[或方法]重载更多地与根据传递的参数类型调用不同的实现有关.使用默认参数只允许您使用较少的参数调用相同的实现. (4认同)
  • 我更喜欢这个答案而不是公认的答案,因为它明确了参数的最小和最大数量应该是多少。(不要为所需的参数提供默认值。)@Scalable - 我同意 Adil 的观点,因为 php 是松散类型的,这实际上就是在 php 中“重载”一个函数的全部意义 - 无论如何,你让读者应该注意的一个有用的观点。 (2认同)

Sea*_*ney 10

对某些人来说这可能是一种愚蠢的行为,但我从Cakephp如何做一些功能并通过改编它来学习,因为我喜欢它创造的灵活性

想法是你有不同类型的参数,数组,对象等,然后你会检测到你传递的内容并从那里开始

function($arg1, $lastname) {
    if(is_array($arg1)){
        $lastname = $arg1['lastname'];
        $firstname = $arg1['firstname'];
    } else {
        $firstname = $arg1;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)


His*_*lal 10

真正的重载(版本3.8)"没有扩展"+"支持闭包"

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

#> 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(closure)
    function func__c(Closure $callback) {
        // your code...
        pre("func__c(".print_r($callback, 1).");", 'print_r(Closure)');
        return $callback($this->name);
    }   
    // 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.', object='.get_class($object).')', __function__);
        pre($object, 'Object: ');
    }
    // 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;

pre(
    $t->func(function($n){
        return strtoupper($n);
    })
, 
'Closure');

#> 6. Call your method by typing first part before __ and add method $args if exist

// 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, object=obj)
Object: obj Object
(
    [x:obj:private] => 10
)
*/

## Passing by Reference:

echo '$val='.$val;
// Output: $val=10

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

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

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

echo '$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;
}
//----------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

  • 你能补充一些如何使用这个类的解释吗? (4认同)

mtp*_*ltz 6

在 PHP 5.6 中,您可以使用splat 运算符 ...作为最后一个参数并取消func_get_args()and func_num_args():

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

example(1, 2);
example(1, 2, 3, 4, 5, 6, 7);
Run Code Online (Sandbox Code Playgroud)

您也可以使用它来解压参数:

$args[] = 1;
$args[] = 2;
$args[] = 3;
example(...$args);
Run Code Online (Sandbox Code Playgroud)

相当于:

example(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)