PHP işlevi aşırı yüklenmesi


196

C ++ geçmişinden geliyor;)
PHP işlevlerini nasıl aşırı yükleyebilirim?

Bir fonksiyon tanımı varsa argüman, diğeri argüman yoksa? PHP ile mümkün mü? Yoksa $ _GET ve POST geçirilen herhangi bir parametre olup olmadığını kontrol etmek için başka eğer kullanmalıyım ?? ve ilişkilendirin?


1
Yalnızca sınıf yöntemlerini aşırı yükleyebilirsiniz, ancak işlevleri kullanamazsınız. Bkz. Php.net/manual/en/language.oop5.overloading.php
Spechal

1
Önceden tanımlanmış bir kümeden bağımsız değişken sayısını açık bir şekilde kontrol eden ve başka bir işlevi yürüten bir işlev oluşturabilirsiniz. Çözümünüzü yeniden tasarlamanız veya arayüzünüzü uygulayan sınıflar kullanmanız iyi olur
kolypto

2
Gibi php.net/manual/en/language.oop5.overloading.php diyor, aşırı yüklenme PHP'nin tanımı tipik bir OOP dili farklıdır. Sadece X'e dayalı özellik ve işlevlerin dinamik olarak yönlendirilmesine izin veren sihirli yöntemlere atıfta bulunuyorlar.
Edwin Daniels

Gelecekteki okuyucular için: @ Spechal'ın neyi kasteddiği, soru için sorulandan farklı bir anlamdır overloading. (Daha fazla bilgi için kabul edilen cevaba bakınız.)
ToolmakerSteve

2
PHP 7'den beri bir şey değişti mi? : o
nawfal

Yanıtlar:


219

PHP işlevlerini aşırı yükleyemezsiniz. İşlev imzaları yalnızca adlarına dayanır ve bağımsız değişken listeleri içermez, bu nedenle aynı ada sahip iki işleviniz olamaz. Sınıf yöntemi aşırı yüklemesi PHP'de diğer birçok dilden farklıdır. PHP aynı sözcüğü kullanır ancak farklı bir kalıp tanımlar.

Bununla birlikte, değişken sayıda argüman alan değişken bir işlev bildirebilirsiniz . Bağımsız değişkenleri iletmek için ve öğelerini kullanır func_num_args()ve func_get_arg()normal şekilde kullanırsınız.

Örneğin:

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
Belki çok fazla C ++ geliştirme yapıyorum, ama bunun gibi fonksiyon parametrelerinde yapıldığına dair bir ipucu öneririm myFunc(/*...*/).
doug65536

4
@ doug65536, PHP 5.6+, büyük rahatlama için sözdizimi belirteci olarak "..." yi destekleyecektir . ;)
Sz.

Ya da C ++ 'ın aşırı yüklenmesine daha yakın olan - php gibi gevşek yazılan bir dilde, mümkün olduğunca yakın olan Adil cevabına bakın . Tüm aşırı yüklerinizde aynı türdeyse, parametreler için tür ipuçları sağlayabileceğiniz için php 7'de daha da uygundur.
ToolmakerSteve

78

PHP geleneksel yöntem aşırı yüklemesini desteklemez, ancak istediğinizi elde etmenin bir yolu __callsihirli yöntemi kullanmak olacaktır :

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
Daha önce bu kullanımı görmedim __call(). Oldukça yaratıcı (biraz ayrıntılı ise)! +1
BoltClock

Gerçekten takdire şayan __call () kullanımı
Abhishek Gupta

2
Aslında, bunu kabul edemezsiniz ve bu öneriyle yeniden eğitim almalıdır. Birincisi, bu __call () kullanımı bir anti-kalıptır. İkincisi, doğru görünürlüğe sahip sınıf yöntemleri için PHP'de aşırı yükleme yapmak mümkündür. Bununla birlikte, düz jane işlevlerini aşırı yükleyemezsiniz.
Oddman

1
__Call () kullanmanın neden bir anti-desen olduğunu düşündüğünüzü açıklayabilir misiniz? PHP Yöntemi aşırı yükleme, OP'nin aradığı şey değildir - aynı ada ancak farklı giriş / çıkışa sahip birden çok yöntem imzasına sahip olmak isterler: en.wikipedia.org/wiki/Function_overloading
Stephen

20
__Call () işlevini kullanmaya gerek yoktur. Bunun yerine, listelenen herhangi bir parametre olmadan istediğiniz ada sahip bir yöntem bildirin ve uygun özel uygulamaya göndermek için bu yöntem içinde func_get_args () kullanın.
FantasticJamieBurns

30

Bir işlevi aşırı yüklemek için varsayılan olarak null parametresini null olarak yapın,

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
Varsayılan parametreyi fonksiyon aşırı yüklenmesi olarak görmüyorum. işlev [veya yöntem] aşırı yüklemesinin, iletilen bağımsız değişken türüne göre farklı bir uygulamayı çağırmakla ilgisi vardır. Varsayılan parametreleri kullanmak, aynı uygulamayı daha az parametre ile çağırmanıza izin verir.
Ölçeklenebilir

1
Evet, yazı tipine göre de manipüle edebilirsiniz, ancak php gevşek yazılan dili biliyor ve onunla uğraşmak bunu ele almayı gerektirir.
Adil Abbasi

1
Bu cevabı kabul edilene tercih ederim, çünkü minimum ve maksimum parametre sayısının ne olması gerektiğini netleştirir. (Gerekli parametreler için varsayılan bir değer vermeyin.) @Scalable - Adil'e katılıyorum, php gevşek bir şekilde yazıldığından, bu overloadphp'de bir işleve gelebilecek etkili bir şeydir - yine de yararlı bir nokta yaparsınız okuyucuların farkında olması gerekir.
ToolmakerSteve

11

Bazıları için hackish olabilir, ancak Cakephp'in bazı işlevleri nasıl yaptığını ve adapte ettiğini bu şekilde öğrendim çünkü yarattığı esnekliği seviyorum

Fikir, farklı türde argümanlarınız, dizileriniz, nesneleriniz vb.

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

1
Hayır, bunu hackish olarak görmüyorum, PHP bunu birçok yerleşik işlev için yapıyor.
BoltClock

Php gevşek yazıldığından, bu tam olarak nasıl bu durumu ele gerekir . Php onun "gerekli hackishness".
ToolmakerSteve

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
Bu sınıfın nasıl kullanılacağına dair biraz açıklama ekleyebilir misiniz?
Justus Romijn

1- Yeni sınıf yarat 2- yüklenebilir. 3- funcname_ () => argüman veya funcname_s gibi fonksiyonlar oluşturun ($ s) => string arg </li>
Hisham Dalal

1
Bu çok güzel bir çözüm. Neden $ o = new $ obj () yapıyorsunuz? Henüz denemedim, ama bu \ $ o = \ $ olması gerektiğini düşünüyorum?
over_optimistic

Bu önemli uyarı için teşekkür ederim, ve ters eğik çizgi kullanacağım, ancak ters eğik çizgi ile ve olmadan çalışır! - Yerel sunucu olarak phpEazy kullanıyorum.
Hisham Dalal

4

Peki buna ne dersin:

function($arg = NULL) {

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

Çalışabilir, ancak aşırı yükün farklı adlara ve anlamlara sahip farklı parametreleri varsa daha az okunabilir.
Mathias Lykkegaard Lorenzen

3

PHP 5.6'da splat operatörünü ... son parametre olarak kullanabilir ve func_get_args()ve func_num_args():

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

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

Bunu, argümanları açmak için de kullanabilirsiniz:

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

Şuna eşittir:

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);
    ?>

Soruyu düzenlemeye ve biçimlendirmeyi kullanmaya çalışın. Cevabınızı daha okunabilir hale getirecek ve daha fazla kullanıcı çekecektir.
Kashish Arora


0

PHP şimdilik aşırı yüklemeyi desteklemiyor. Umarım bu diğer programlama dilleri gibi diğer sürümlerde de uygulanacaktır.

Bu kütüphaneye göz at, Bu kapanış açısından PHP Overloading kullanmanıza izin verecektir. https://github.com/Sahil-Gulati/Overloading


1
bunun gibi bir ifade yapacaksanız, atıfta bulunduğunuz sürümleri gerçekten içermelidir, bu şekilde insanlar yorumunuzun gelecekteki bir tarihte gördüklerinde ne kadar güncel
olmadığını bilirler

0

Ne yazık ki C # 'da yapıldığı gibi PHP aşırı yük yoktur. Ama küçük bir numaram var. Varsayılan null değerleri olan bağımsız değişkenler bildirir ve bunları bir işlevde kontrol ederim. Bu şekilde işlevim argümanlara bağlı olarak farklı şeyler yapabilir. Aşağıda basit bir örnek verilmiştir:

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
Bir yıl sonra yeni bir yazı yazmadan önce lütfen mevcut tüm cevapları okuyun. Bu teknik yukarıdaki cevaplarda zaten iki kez gösterilmiştir. 2013'te bir kez ve 2014'te tekrar.
ToolmakerSteve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.