Перегрузка функций PHP



исходя из фона C++;)

Как я могу перегрузить функции PHP?



одно определение функции, если есть какие-либо аргументы, и другое, если нет аргументов?
Возможно ли это в PHP? Или я должен использовать if else, чтобы проверить, есть ли какие-либо параметры, переданные из $_GET и POST?? и связать их?

872   10  

10 ответов:

вы не можете перегрузить функции 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);

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

    }

}

чтобы перегрузить функцию, просто передайте параметр как 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');

это может быть хакерским для некоторых, но я узнал этот путь от того, как Cakephp выполняет некоторые функции и адаптировал его, потому что мне нравится гибкость, которую он создает

идея в том, что у вас есть разные типы аргументов, массивов, объектов и т. д., Затем вы обнаруживаете, что вам передали, и идете оттуда

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

реальная перегрузка (версия 3.8)" без расширения " + "поддержка закрытия"

/*******************************
 * author  : [email protected] 
 * 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;
}
//----------------------------------------------------------

выход:

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

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

)
);

---- Closure ----

TEST-1

реальная перегрузка " без расширения "(версия 3.7)

<?php

/*******************************
 * author  : [email protected] 
 * 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

Реальная Перегрузка (Версия 3.5):

/*******************************
 * author  : [email protected] 
 * 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();

Реальная Перегрузка (Версия 3.1):

/*******************************
 * author  : [email protected] 
 * 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() );

Как насчет этого:

function($arg = NULL) {

    if ($arg != NULL) {
        etc.
        etc.
    }
}

в PHP 5.6 вы можете использовать оператор splat... как последний параметр и покончить с 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);
<?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);
    ?>

PHP пока не поддерживает перегрузку. Надеюсь, что это будет реализовано в других версиях, таких как другие языки программирования.

проверьте эту библиотеку, это позволит вам использовать перегрузку PHP с точки зрения закрытия. https://github.com/Sahil-Gulati/Overloading

к сожалению, в 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);

Comments

    Ничего не найдено.