PHP function overloading

2019-01-01 01:51发布

Coming from C++ background ;)
How can I overload PHP functions?

One function definition if there are any arguments, and another if there are no arguments? Is it possible in PHP? Or should I use if else to check if there are any parameters passed from $_GET and POST?? and relate them?

10条回答
萌妹纸的霸气范
2楼-- · 2019-01-01 02:07

To over load a function simply do pass parameter as null by default,

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');
查看更多
查无此人
3楼-- · 2019-01-01 02:07

Real Overload (Version 3.8) "without extending" + "support closures"

/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.8
 * create on : 2017-09-17
 *****************************/


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

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

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

    // func(closure)
    function func__c(Closure $callback) {
        pre("func__c(".print_r($callback, 1).");", 'print_r(Closure)');
        return $callback($this->name);
    }   
}

//----------------------------------------------------------
// Start
$t = new test;

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

//----------------------------------------------------------
function pre($mixed, $title=null, $print=true){
    $output = "";
    if(empty($mixed)){
        $output .= "<div><h3>-->Empty $title<--</h3></div>";
        if($print) echo $output;
        else return $output;
    }
    $output .= "<fieldset>";
    if($title){$output .= "<legend><h2>$title</h2></legend>";}
    $output .= '<pre>';
    $output .= print_r($mixed, 1);
    $output .= '</pre>';
    $output .= "</fieldset>";
    if($print) echo $output;
    else return $output;
}
//----------------------------------------------------------

Output:

---- print_r(Closure) ----

func__c(Closure Object
(
    [parameter] => Array
        (
            [$n] => 
        )

)
);

---- Closure ----

TEST-1

Real Overload "Without extending" (Version 3.7)

<?php

/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.7
 * date    : 2014-12-01
 *****************************/

class Overloadable
{
    static function call($obj, $method, $params=null) {
        // 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);
            #return $obj->$suffix_method_name($params);
        } else {
            $class = get_class($obj);
            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':      $c .= 'o'; break;
                    case 'resource':    $c .= 'r'; break;
                    case 'string':      $c .= 's'; break;
                }
            }
        }
        return $c;
    }
    // Get a reference variable by name
    static function &refAccess($var_name) {
        $r =& $GLOBALS["$var_name"]; 
        return $r;
    }

}


class test 
{
    // Call Overloadable class 
    // you must copy this method in your class to activate overloading
    function __call($method, $args) {
        return Overloadable::call($this, $method, $args);
    }
    // myFunction(void)
    function myFunction__() {
        echo 'myFunction(void)';
    }
    // myFunction(integer)
    function myFunction__i($int) {
        echo 'myFunction(integer='.$int.')';
    }
    // myFunction(string)
    function myFunction__s($string) {
        echo 'myFunction(string='.$string.')';
    }    
    // myFunction(string)
    function myFunction__so($string, $object) {
        echo 'myFunction(string='.$string.', object='.get_class($object).')';
        echo '<pre>Object: ';
        print_r($object);
        echo '</pre>';
    }
    // anotherFunction(array)
    function anotherFunction__a($array) {
        echo 'anotherFunction('.print_r($array, 1).')';
        $array[0]++;        // change the reference value
        $array['val']++;    // change the reference value
    }
    // anotherFunction(string, integer)
    function anotherFunction__si($key, $value) {
        echo 'anotherFunction(string='.$key.', integer='.$value.')';
        // 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;
}
//----------------------------------------------------------

// Start
$t = new test;

// Call first method with no args:
$t->myFunction(); 
// Output: myFunction(void)
echo '<hr>';

$t->myFunction($val);
// Output: myFunction(integer=10)
echo '<br>';

$t->myFunction("hello");
// Output: myFunction(string=hello)
echo '<br>';

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

## Passing by Reference:

echo '<hr>';
echo '$val='.$val;
// Output: $val=10
echo '<br>';
$t->anotherFunction(array(&$val, 'val'=>&$val));
// Output: anotherFunction(Array ( [0] => 10 [val] => 10 ) )
echo '<br>';
echo '$val='.$val;
// Output: $val=12

echo '<hr>';
$t->anotherFunction('val', $val);
// Output: anotherFunction(string=val, integer=12)
echo '<br>';
echo '$val='.$val;
// Output: $val=36

Real Overload (Version 3.5):

/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.5
 * date    : 2014-11-16
 *****************************/

class Overloadable 
{
    // Magic Method
    public function __call($method, $params) {
        $class = get_class($this);
        // Get real method name
        $suffix_method_name = $method.$this->getMethodSuffix($method, $params);

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

    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 'integer':     $c .= 'i'; break;
                    case 'double':      $c .= 'd'; break;
                    case 'string':      $c .= 's'; break;
                    case 'array':       $c .= 'a'; break;
                    case 'object':      $c .= 'o'; break;
                    case 'resource':    $c .= 'r'; break;
                    case 'NULL':        $c .= 'n'; break;
                }
            }
        }
        return $c;
    }
    // Get reference variable by name
    function &refAccess($var_name){
        $r =& $GLOBALS["$var_name"]; 
        return $r;
    }
}

//------------------------------------------------------------------------//
## Inherit "Overloadable" class to enable overloading
class test extends Overloadable
{
        // myFunction(void)
        function myFunction__() {           
            echo  "Hi<br>";
        }

        // myFunction(integer, string)
        function myFunction__is($a, $s) {
            echo  "$a, $s<br>";
        }

        // myFunction(array)
        function myFunction__a($a) {
            $a[0]++; // change the reference value
            $a[1]++;  // change value locally (method scope) 
        }

        // myFunction(integer)
        function myFunction__i($b) {
            // $GLOBALS['val2']
            $b2 =& $this->refAccess('val2');
            $b2 *= 3;   // change the reference value
        }

        // myFunction(string, string)
        function myFunction__ss($a, $b) {
            // $this->refAccess('obj')->plus()
            $this->refAccess($a)->plus();

            #$b1 =& $GLOBALS["$b"]; 
            $b1 =& $this->refAccess($b); 
            $b1++;
            $b1++;
        }

        // myFunction(object, integer, array)
        function myFunction__oia($a, $b, $ary) {
            // Get arguments names
            $obj_name = $ary[0];
            $val_name = $ary[1];

            // Get argument reference
            $a1 =& $this->refAccess($obj_name); 
            $a1->plus();

            $b1 =& $this->refAccess($val_name);
            $b1+= $b;
        }

        // Just a normal method
        function welcome(){
            echo "Welcome!";
        }

}
//------------------------------------------------------------------------//
// Some data types to work with:
class  obj {
    private $v=0;
    function plus(){
        $this->v++;
    }
    function result(){
        return $this->v;
    }
}
$val  = 10;
$val2 = 10;
$obj = new obj();

// Show Default values
echo "\$val = $val, \$val2 = $val2, ";
echo 'obj->v =' . $obj->result()."<hr>";
//------------------------------------------------------------------------//

// Start
$t = new test();


// Call first method with no args:
echo 'myFunction__():<br>';
$t->myFunction();
echo "<hr>";


echo 'myFunction__is(integer, string):<br>';
$t->myFunction($val, 'text');
echo "\$val = $val, \$val2 = $val2<hr>";


echo 'myFunction__i(integer):<br>';
$t->myFunction($val);
echo "\$val = $val, \$val2 = $val2<hr>";

## Passing by Reference:

// 1) The best way to pass arguments
echo 'myFunction__a(array):<br>';
//Passing first item by reference
$t->myFunction(array(&$val, $val2));
echo "\$val = $val, \$val2 = $val2<hr>";

// 2) Passing arguments names
echo 'myFunction__ss(string, string):<br>';
// Pass object name and variable name
$t->myFunction('obj', 'val');
echo "\$val = $val, \$val2 = $val2, ";
echo 'obj->v =' . $obj->result()."<hr>";

// 3) Passing arguments values and names
echo 'myFunction__oia(object, integer, array):<br>';
// Pass object, integer values and passing there names as array
$t->myFunction($obj, $val, array('obj', 'val'));
echo "\$val = $val, \$val2 = $val2, ";
echo 'obj->v =' . $obj->result()."<hr>";

// Just a normal method
echo 'welcome():<br>';
$t->welcome();

Real Overload (Version 3.1):

/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.1
 * date    : 2013-04-11
 *****************************/

class overloadable
{
    protected $fname = null;
    protected $fargs = array();

    //--------------------------------------------------//
    function set($obj, $fname, $args){
        $n = ''; 
        $type = $this->getType($args); 
        $n  = "\$o = new $obj();\n";
        $n .= "if(method_exists(\$o, '$fname"."_$type')){\n";
        $n .= "\t\$r = \$o->$fname"."_$type(". $this->getArgsName($args) .");\n";
        $n .= "}else{\n\t\$r = null;\n";
        $n .= "\ttrigger_error('function ".$fname."_".$type." is not exist!');\n}";
        eval("\$r = $n;");
        return $r;
    }
    //--------------------------------------------------//
    function getType($args) {
        $argType = array();
        foreach($args as $i=>$val) {
            $argType[$i][] = $this->getSuffix($val, $i) ;
        }
        $s = '';
        if(is_array($argType)){
            foreach($argType as $type){
                $s  .= implode('', $type);
            }
            return $s;
        }
        return implode('', $argType);
    }   
    //--------------------------------------------------//
    function getSuffix($byValarg, $i) {
            if( is_numeric($byValarg) ) {
                $type = 'N'; 
                $this->fargs['N'.$i] = $byValarg;
            } elseif( is_array($byValarg) ) {
                $type = 'A';
                $this->fargs['A'.$i] = $byValarg;
            } elseif( is_object($byValarg) ) {
                $type = 'O'; 
                $this->fargs['O'.$i] = $byValarg;
            } elseif( is_resource($byValarg) ) {
                $type = 'R'; 
                $this->fargs['R'.$i] = $byValarg;
            } else {
                $type = 'S'; 
                $this->fargs['S'.$i] = $byValarg;
            }   
            return $type;
    }
    //--------------------------------------------------//
    function getArgsName($args){
        $r = array();
        $ary = array_keys($this->fargs);
        foreach( $ary as $k=>$v){
            $r[]='$this->fargs["'.$v.'"]';
        }
        return implode(", ", $r);
    }
    //--------------------------------------------------//  
    function __call($name, $args){
        $this->fargs = array();
        return $this->set(get_class($this), $name, $args);
    }
    //--------------------------------------------------//  
}


class test2 extends overloadable {
    function foo_(){
        echo 'foo - no args';
    }
    function foo_S($s){
        echo "foo - one string $s";
    }
    function foo_SS($s1, $s2){
        echo "foo - tow strings $s1, $s2";
    }   
    function foo_SN($s, $n){
        echo "foo - string and number $s, $n";
    }
    function foo_A($ary){
        print_r($ary);
    }
    function foo_AA($ary1, $ary2){
        if(is_array($ary1) && is_array($ary2)){
            echo "foo - tow arrays";
        }else{echo 0;}
    }   
    function foo_O($obj){
        echo "foo - ";
        print_r($obj);
    }
    function hi(){
        echo "hi - welcome!";
    }
}

echo '<pre>';
$t = new test2();

echo '<br />foo_: ';
print_r( $t->foo() );

echo '<br />foo_s: ';
print_r( $t->foo('a') );

echo '<br />foo_ss: ';
print_r( $t->foo('a', 'b') );

echo '<br />foo_sn: ';
print_r( $t->foo('a', 2) );

echo '<br />foo_snn: ';
print_r( $t->foo('s', 2, 9) );

echo '<br />foo_a: ';
print_r( $t->foo(array(4,5,6,7)) );

echo '<br />foo_aa: ';
print_r( $t->foo( array(5,6,7), array(8,9,10) ) );

echo '<br />foo_o: ';
print_r( $t->foo($t) );

echo '<br />hi: ';
print_r( $t->hi() );
查看更多
人气声优
4楼-- · 2019-01-01 02:08

You cannot overload PHP functions. Function signatures are based only on their names and do not include argument lists, so you cannot have two functions with the same name. Class method overloading is different in PHP than in many other languages. PHP uses the same word but it describes a different pattern.

You can, however, declare a variadic function that takes in a variable number of arguments. You would use func_num_args() and func_get_arg() to get the arguments passed, and use them normally.

For example:

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);
查看更多
伤终究还是伤i
5楼-- · 2019-01-01 02:10

What about this:

function($arg = NULL) {

    if ($arg != NULL) {
        etc.
        etc.
    }
}
查看更多
何处买醉
6楼-- · 2019-01-01 02:12
<?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);
    ?>
查看更多
零度萤火
7楼-- · 2019-01-01 02:14

PHP doesn't support traditional method overloading, however one way you might be able to achieve what you want, would be to make use of the __call magic method:

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

    }

}
查看更多
登录 后发表回答