Question

À partir de la version 5.3, PHP prend en charge la liaison tardive pour les méthodes statiques. Bien qu’il s’agisse d’une fonctionnalité utile, il n’ya que plusieurs cas où son utilisation est réellement nécessaire (par exemple, le modèle d’enregistrement actif).

Considérez ces exemples:

1. Constructeurs de commodité ( :: create () )

class SimpleObject
{
    public function __construct() { /* ... */ }

    public static function create()
    {
        return new static; // or: return new self;
    }
}

Si cette classe peut être étendue (cependant, elle ne l'est pas par une classe du même package), si une liaison statique tardive est utilisée simplement pour la rendre plus facile (sans avoir à réécrire le :: create () et, plus important encore, sans avoir à vous rappeler cela)?

Remarque: cet idiome est utilisé pour contourner l'impossibilité d'appeler des méthodes sur des objets simplement construits: new SimpleObject () - > doStuff () n'est pas valide en PHP.

2. Constantes de classe

class TagMatcher
{
    const TAG_PATTERN = '/\<([a-z\-]+?)\>/i';

    private $subject;

    public function construct($subject) { $this->subject = $subject; }

    public function getAllTags()
    {
        $pattern = static::TAG_PATTERN;
        preg_match_all($pattern, $this->subject);
        return $pattern[1];
    }
}

La raison d'utiliser static :: dans cet exemple est similaire au précédent. Il est utilisé simplement parce que cette classe peut être conçue pour correspondre à des balises formées différemment, simplement en l'étendant et en remplaçant la constante.

Donc, pour résumer tout cela, ces utilisations (et des utilisations similaires) de la dernière liaison statique sont-elles excessives? Existe-t-il des performances notables? De plus, l’utilisation fréquente d’une liaison tardive réduit-elle l’amélioration globale des performances donnée par les caches opcode?

Était-ce utile?

La solution

  

Donc, pour résumer tout cela, ces utilisations (et des utilisations similaires) de la dernière liaison statique sont-elles excessives? Existe-t-il des performances notables? De plus, l’utilisation fréquente d’une liaison tardive réduit-elle l’amélioration globale des performances donnée par les caches opcode?

L'introduction d'une liaison statique tardive corrige une faille dans le modèle d'objet de PHP. Il ne s'agit pas de performance, mais de sémantique.

Par exemple, j'aime utiliser des méthodes statiques chaque fois que la mise en œuvre de la méthode n'utilise pas $ this . Ce n’est pas parce qu’une méthode est statique que vous ne voulez pas la remplacer parfois. Avant PHP 5.3, le comportement était qu'aucune erreur n'était signalée si vous surchargiez une méthode statique, mais PHP utilisait simplement la version du parent en mode silencieux. Par exemple, le code ci-dessous affiche 'A' avant PHP 5.3. C'est un comportement hautement inattendu.

La liaison statique tardive le corrige, et maintenant le même code affiche "B".

<?php
class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    static::who();
  }
}

class B extends A {
  public static function who() {
    echo __CLASS__;
  }
}

B::test();
?>

Autres conseils

Les méthodes

statiques (liées tôt ou tardivement) créent un couplage étroit et (donc) réduisent la testabilité. vous pouvez créer de gros programmes en PHP sans utiliser plus que quelques appels statiques. pour moi, les méthodes statiques tardives ne sont pas des fonctionnalités.

modifier pour répondre à la question de Marco Demaio, Comment la méthode statique réduit-elle la testabilité?

Je suis désolé si cela vous semble évident. Les membres statiques (données et méthodes) sont utiles et ne causent pas de tort s'ils sont utilisés de manière responsable. Je faisais allusion à leur mauvaise utilisation courante.

Disons que vous avez une application Web qui utilise une base de données SQL. vos objets métier peuvent récupérer des données à l'aide d'une interface statique ou par polymorphisme. soit

class MyBusinessObject
extends...
{
  public function doThisOrThat(...)
  {
    $results = db::query('sql string...');
    ...
  }
}

ou

class MyBusinessObject
extends...
{
  public function __construct(dbconn $db)
  {
    $this->db = $db;
  }
  private $db;
  public function doThisOrThat(...)
  {
    $results = $this->db->query('sql string...');
    ...
  }
}

ce dernier est plus facile à tester (comme dans: je veux tester que la chaîne SQL construite à partir de telles entrées est telle ou telle) car il est plus facile de créer une autre implémentation du dbconn que de changer la signification de db :: . pourquoi tu veux non plus? car vous n'avez pas besoin d'une vraie base de données pour tester le comportement de composition SQL, et en fait, il est plus facile de tester sans une vraie base de données. de plus, il est plus facile d’empêcher le consommateur SQL de se poser si vos tests portent sur un autre aspect de la CUT (Code Under Test).

tester implique toujours de mentir le code testé sur ses collaborateurs et de s’abstenir d’interfaces statiques (le "double-colon" ou le "quadridot") signifie que le mensonge n’est pas nécessairement une opération chirurgicale massive, ce qui est un avantage, le code testé provient du code de production, moins les résultats du test sont significatifs.

Là où je trouve nécessaire d'utiliser une liaison statique tardive, c'est de permettre de se moquer des méthodes statiques pour les tests unitaires avec PHPUnit. Le problème que j’ai, c’est que je n’aime pas changer le code strictement pour permettre de me moquer, mais je peux surmonter cela.

Pour répondre à votre question, toutefois, je parierais que quel que soit le coût de performance que cela comporte, il sera dérisoire par rapport à la plupart des programmes exécutés. En d'autres termes, cela ne fera pas une différence notable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top