214 votes

Surcharge des fonctions PHP

Je viens d'un milieu C++ ;)
Comment surcharger les fonctions PHP ?

Une définition de fonction s'il y a des arguments, et une autre s'il n'y a pas d'arguments ? Est-ce possible en PHP ? Ou dois-je utiliser if else pour vérifier s'il y a des paramètres passés par $_GET et POST ? et les mettre en relation ?

1 votes

Vous pouvez uniquement surcharger les méthodes des classes, mais pas les fonctions. Voir php.net/manual/fr/language.oop5.overloading.php

1 votes

Vous pouvez créer une fonction qui vérifie explicitement le nombre d'arguments et exécute une autre fonction, à partir d'un ensemble prédéfini de ceux-ci. Cependant, vous feriez mieux de revoir votre solution ou d'utiliser des classes qui implémentent votre interface.

3 votes

Comme le php.net/manual/fr/language.oop5.overloading.php dit, la définition de PHP de la surcharge est différente de celle du langage OOP typique. Il s'agit simplement de méthodes magiques qui permettent un routage dynamique des propriétés et des fonctions en fonction de X.

238voto

BoltClock Points 249668

Vous ne pouvez pas surcharger les fonctions PHP. Les signatures des fonctions sont basées uniquement sur leurs noms et n'incluent pas les listes d'arguments, vous ne pouvez donc pas avoir deux fonctions avec le même nom. Classe surcharge des méthodes est différent en PHP que dans beaucoup d'autres langages. PHP utilise le même mot mais il décrit un modèle différent.

Vous pouvez toutefois déclarer un fonction variadique qui prend en compte un nombre variable d'arguments. Vous utiliserez func_num_args() et func_get_arg() pour récupérer les arguments passés, et les utiliser normalement.

Par exemple :

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 votes

Peut-être que j'ai trop fait de développement C++, mais je suggérerais un indice que cela est fait dans les paramètres de la fonction comme myFunc(/*...*/) .

5 votes

@doug65536, PHP 5.6+ le supporte. "..." comme jeton syntaxique pour notre plus grand soulagement ;)

0 votes

Ou voir La réponse d'Adil qui est plus proche de la surcharge du C++ - aussi proche qu'il est possible de l'être, dans un langage faiblement typé comme le php. C'est encore plus approprié en php 7, car vous pouvez fournir des indications de type pour les paramètres, s'ils sont du même type dans toutes vos surcharges.

85voto

Stephen Points 5339

PHP ne supporte pas la surcharge traditionnelle des méthodes, mais une façon d'obtenir ce que vous voulez est d'utiliser la fonction de surcharge des méthodes. __call méthode magique :

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

    }

}

23 votes

Je n'ai pas vu cette utilisation de __call() avant. Plutôt créatif (même si un peu verbeux) ! +1

1 votes

Utilisation vraiment admirable de __call()

3 votes

En fait, je ne peux pas être d'accord avec cela, et je dois faire un effort de réadaptation avec cette suggestion. D'abord, cette utilisation de __call() est un anti-modèle. Deuxièmement, il est possible de surcharger en PHP des méthodes de classe qui ont une visibilité correcte. Vous ne pouvez pas, cependant, surcharger des fonctions ordinaires.

31voto

Adil Abbasi Points 565

Pour surcharger une fonction, il suffit de passer le paramètre comme nul par défaut,

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 votes

Je ne considère pas les paramètres par défaut comme une surcharge de fonction. La surcharge de fonction [ou de méthode] a plus à voir avec l'appel d'une implémentation différente en fonction du type d'argument passé. L'utilisation de paramètres par défaut vous permet seulement d'appeler la même implémentation avec la commodité de moins de paramètres.

1 votes

Oui, vous pouvez le manipuler sur la base de type aussi bien mais comme si vous connaissez le langage php loosely typed et traiter avec lui exige d'aborder cela.

2 votes

Je préfère cette réponse à celle qui a été acceptée, car elle rend explicite le nombre minimum et maximum de paramètres. (Ne fournissez pas de valeur par défaut pour les paramètres qui sont requis.) @Scalable - Je suis d'accord avec Adil que, puisque php est typée de manière lâche, c'est effectivement tout ce que cela peut signifier en php de overload une fonction - néanmoins, vous soulevez un point utile que les lecteurs devraient connaître.

11voto

SeanDowney Points 5299

C'est peut-être un bricolage pour certains, mais j'ai appris de cette façon comment Cakephp fait certaines fonctions et je l'ai adaptée parce que j'aime la flexibilité qu'elle crée.

L'idée est que vous avez différents types d'arguments, des tableaux, des objets, etc., puis vous détectez ce qui vous a été passé et vous partez de là.

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

1 votes

Non, je ne vois pas cela comme du piratage, PHP le fait pour beaucoup de ses fonctions intégrées.

0 votes

Parce que le langage php est vaguement typé, c'est exactement comme ça qu'on peut debe gérer cette situation. C'est le "hackishness nécessaire" en php.

11voto

Hisham Dalal Points 29

Une véritable surcharge :

/*******************************
 * 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() );

5 votes

Pourriez-vous ajouter quelques explications sur l'utilisation de cette classe ?

0 votes

1- créer une nouvelle classe 2- étendre overloadable. 3- créer des fonctions comme funcname_() => no args ou comme funcname_s($s) => string arg</li>

1 votes

C'est une solution plutôt cool. Pourquoi faites-vous $o = new $obj() ? Je n'ai pas encore essayé, mais je pense que ça devrait être \$o = \$this ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X