3 votes

Stocker une fonction de fermeture dans une propriété de classe en PHP

Ok j'ai le code ci-dessous

<?php
    class foo{
       public $bar = NULL;

       public function boo(){
          $this->bar();
       }
    }

    $mee = new foo();

    //save a closure function on the property
    $mee->bar = function(){
        echo 'hahaha';
    };

    //invoke the closure function by using a class method
    $mee->boo();
?>

et vous pouvez le voir fonctionner ici http://codepad.org/s1jhi7cv

Maintenant, ce que je veux ici est de stocker la fonction de fermeture sur la méthode de la classe.

Les fermetures sont possibles comme je l'ai lu dans la documentation ici. http://php.net/manual/en/functions.anonymous.php

est-ce possible ? ai-je fait une erreur ? corrigez-moi s'il vous plaît.

14voto

DaveRandom Points 45661

Votre exemple de code sur codepad.org ne fonctionne pas car codepad.org utilise PHP 5.2.5, et le support de la fermeture n'a été ajouté qu'en 5.3.

Cependant, votre code ne fonctionnera pas non plus dans une version de PHP qui supporte les fermetures, même si vous obtiendrez une erreur différente : http://codepad.viper-7.com/Ob0bH5

Il s'agit d'une limitation de PHP à l'heure actuelle. $obj->member() cherche une méthode nommée member et ne regardera pas les propriétés pour voir si elles sont appelables. C'est, franchement, ennuyeux.

Le seul moyen que je connaisse pour que cela fonctionne sans call_user_func() / call_user_func_array() est :

public function boo() {
   $func = $this->bar;
   $func();
}

4voto

hakre Points 102271

Vous devez exploiter certaines fonctionnalités magiques de PHP ( __call ) pour en faire usage. Prolonger de Extendable par exemple :

class Extendable {
    static function import($context) {
        $self = new static();
        while (is_callable($context)) $context = $context($self);
        if (is_array($context) || is_object($context) || is_a($context, 'Traversable')) {
            foreach($context as $key => $value)
                $self->$key = &$value; # preserve keys if
        }
        return $self;
    }
    public function __call($name, $args) {
        if (isset($this->$name) && is_callable($this->$name)) {
            return call_user_func_array($this->$name, $args);
        }
        throw new BadFunctionCallException(sprintf('Undefined function %s.', $name));
    }
}

Et vous pouvez faire le travail. Ce n'est pas si agréable. Le contexte et les exemples sont dans un de mes articles de blog :

Vous pouvez également mettre en œuvre cette fonctionnalité magique de manière naturelle.

3voto

greg Points 1312

Utilice call_user_func() función:

<?php
    class foo{
       public $bar = NULL;

       public function boo(){
          call_user_func($this->bar);
       }
    }

    $mee = new foo();

    //save a closure function on the property
    $mee->bar = function(){
        echo 'hahaha';
    };

    //invoke the closure function by using a class method
    $mee->boo();

Cela affichera "ahahah"

J'espère que cela vous aidera.

2voto

Matteo Tassinari Points 6496

Vous ne serez pas en mesure de le faire.

Prenez par exemple ce code :

class T {
  function foo() {
    echo 'T::foo';
  }
}

$t = new T;
$t->foo = function() {
  echo 'Closure::foo';
};
$t->foo();

Cela fonctionne bien avec PHP 5.4.6 et/ou PHP 5.3.16, mais il en résulte que T::foo à être imprimé.

Cela se produit parce que les méthodes, en PHP, ne sont pas des propriétés de classe modifiables, comme elles le sont par exemple en javascript.

Cependant,

$foo = $t->foo;
$foo();

imprimera Closure::foo comme prévu.

1voto

Petah Points 18432

PHP n'est pas un langage basé sur des prototypes, vous ne pouvez donc pas redéfinir les fonctions.

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