Maison  >  Article  >  développement back-end  >  Comprendre le modèle de proxy des modèles de conception PHP dans un article

Comprendre le modèle de proxy des modèles de conception PHP dans un article

齐天大圣
齐天大圣original
2020-07-31 16:59:002355parcourir

Le modèle proxy est un modèle de conception structurelle, ciblant la structure classique dans laquelle les classes et les objets sont combinés. Le modèle de proxy est également un modèle de conception fréquemment utilisé sur lequel nous devons nous concentrer. Il peut ajouter des fonctions supplémentaires sans modifier l'objet cible.

Définition

Le modèle de proxy (Proxy) fournit un proxy pour d'autres objets pour contrôler l'accès à cet objet. Utilisez le modèle de proxy pour créer un objet proxy, laissez l'objet proxy contrôler l'accès à l'objet cible (l'objet cible peut être un objet distant, un objet coûteux à créer ou un objet qui nécessite un contrôle de sécurité), et vous pouvez ajoutez quelques extras sans changer la fonction de l'objet cible.

Problème

Actuellement, le système dispose d'une classe de connexion pour la connexion et l'enregistrement des utilisateurs. Le pseudocode est le suivant :

class UserLogin
{
    // …… 省略属性和部分方法
    
    public function login ($name, $pass)
    {
        // 登录业务
    }
    
    public function reg ($name, $pass)
    {
        // 注册业务
    }
}

Maintenant, nous souhaitons ajouter une fonction à l'activité de connexion et d'enregistrement des utilisateurs - limitation actuelle, afin que le client puisse limiter la fréquence d'appel de cette méthode à un maximum de 5 fois par seconde. Maintenant, implémentons cette fonction. Le pseudo-code est le suivant :

class UserLogin
{
    // …… 省略属性和部分方法
    
    public function login ($name, $pass)
    {
        // 限流
        $limit = new Limit();
        if ($limit->restrict()) {
            // ……
        }
        
        // 登录业务
    }
    
    public function reg ($name, $pass)
    {
        // 限流
        $limit = new Limit();
        if ($limit->restrict()) {
            // ……
        }
        
        // 注册业务
    }
}

Jetez un œil au code ci-dessus. Premièrement, le code limitant actuel envahit le code métier et est fortement couplé au code métier. code des affaires. Deuxièmement, les limitations actuelles n’ont rien à voir avec le code des affaires et violent le principe de responsabilité unique.

Implémentation

Ensuite, nous réécrivons le code ci-dessus en utilisant le mode proxy. Le code réécrit ressemble à ceci :

interface IUserLogin
{
    function login ();
    function register ();
}

class UserLogin implements IUserLogin
{
    // …… 省略属性和部分方法
    
    public function reg ($uname, $pass)
    {
        // 注册业务
    }
    
    public function login ($uname, $pass)
    {
        // 登录业务
    }
}

class UserLoginProxy implements IUserLogin
{
    private $limit = null;
    private $login = null;
    
    public function __construct(Limit $limit, Login $login)
    {
        $this->limit = $limit;
        $this->login = $login;
    }
    
    public function login($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return $this->login->login($uname, $pass);
    }
    
    public function register($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return $this->login->register($uname, $pass);
    }
}

. La méthode ci-dessus est basée sur l'idée de conception d'interface plutôt que sur la programmation d'implémentation. Mais si la classe d'origine ne définit pas d'interface, ou si cette classe n'est pas développée et maintenue par nous, alors comment implémenter le mode proxy ?

Pour l'extension de cette classe externe, nous utilisons généralement l'héritage.

class UserLogin
{
    public function reg ($uname, $pass)
    {
        // 注册业务
    }
    
    public function login ($uname, $pass)
    {
        // 登录业务
    }
}

class UserLoginProxy extends Login
{
    private $limit = null;
    
    public function __construct(Limit $limit, Login $login)
    {
        $this->limit = $limit;
        $this->login = $login;
    }
    
    public function login($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return parent::login($uname, $pass);
    }
    
    public function reg($uname, $pass)
    {
        if ($this->limit->restrict()) {
            // ...
        }
        return parent::register($uname, $pass);
    }
}

Regardez le code ci-dessus. Y a-t-il des problèmes ? Vous constaterez que le code similaire

if ($this->limit->restrict()) {
    // ...
}

apparaît deux fois. Maintenant, nous ajoutons simplement la fonction de limitation actuelle à deux méthodes. Si la classe UserLogin a 10 méthodes et que nous voulons ajouter la fonction de limitation actuelle à chaque méthode, nous devons alors copier ce code 10 fois. Si nous voulons ajouter une fonction de limitation de courant à toutes les méthodes de 10 classes et que chaque classe dispose de 10 méthodes, alors le code de limitation de courant ci-dessus sera répété 100 fois.

Bien sûr, vous direz que je peux encapsuler le code limitant actuel dans une fonction pour résoudre le problème ci-dessus ? Mais il reste un problème qui ne peut pas être résolu. Chaque méthode de la classe d'origine doit être réimplémentée dans la classe proxy. Tout comme il existe des méthodes reg et login dans la classe d'origine ci-dessus, il existe également des méthodes reg et login dans la classe proxy.

Procuration dynamique

Comment résoudre les problèmes ci-dessus, nous pouvons utiliser un proxy dynamique pour le résoudre. Si vous souhaitez utiliser un proxy dynamique, vous devez comprendre et utiliser le mécanisme de réflexion en PHP.

php dispose d'une API de réflexion complète, ajoutant la possibilité de procéder à l'ingénierie inverse des classes, des interfaces, des fonctions, des méthodes et des extensions. De plus, l'API Reflection fournit des méthodes pour extraire les commentaires de documentation des fonctions, classes et méthodes. Concernant les connaissances liées à la réflexion PHP, je n'entrerai pas dans les détails ici. Vous pouvez vérifier les informations pertinentes par vous-même.

Notez que l'utilisation de la réflexion consomme beaucoup de performances, veuillez donc ne pas l'utiliser dans des circonstances normales.

Montrons comment utiliser la réflexion pour implémenter un proxy dynamique. Le pseudo-code est le suivant :

class UserLogin
{
    public function reg ($uname, $pass)
    {
        // 注册业务
        echo '注册业务' . PHP_EOL;
    }
    public function login ($uname, $pass)
    {
        // 登录业务
        echo '登录业务' . PHP_EOL;
    }
}
class LimitProxy
{
    // 用来保存多个实例对象
    private $target = [];
    public function __construct(Object $obj)
    {
        $this->target[] = $obj;
    }
    public function __call($name, $arguments)
    {
        foreach ($this->target as $obj) {
            $ref = new \ReflectionClass($obj);
            if ($method = $ref->getMethod($name)) {
                if ($method->isPublic() && !$method->isAbstract()) {
                    // 限流
                    echo "这里是限流业务处理" . PHP_EOL;
                    $result = $method->isStatic() ? $method->invoke(null, $obj, ...$arguments) : $method->invoke($obj, ...$arguments);
                    return $result;
                }
            }
        }
    }
}

Le code de test est le suivant :

$login = new Login();
$loginProxy = new LimitProxy($login);
$loginProxy->reg('gwx', '111111');
$loginProxy->login('james', '111111111');

Scénario d'application

  • Contrôle d'accès (agent de protection). Par exemple, le système dispose d'un module de commande. À l'origine, ce module disposait également d'un contrôle des autorisations, mais nous souhaitons désormais qu'il ne soit accessible qu'aux clients disposant d'adresses IP spécifiées. Nous pouvons ensuite utiliser le mode proxy.

  • L'exécution locale de services distants (proxy distant) convient aux situations où l'objet de service est situé sur un serveur distant.

  • Développer certaines exigences non fonctionnelles dans le code métier, telles que : limitation de courant, statistiques, journalisation

  • Applications de mise en cache, par exemple, ajouter un proxy de cache Lorsque le cache existe, le proxy de cache est appelé pour obtenir les données mises en cache. Lorsque le cache n'existe pas, l'interface d'origine est appelée.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn