Brève analyse du processus en cours d'exécution de Pimple (conteneur PHP)

藏色散人
Libérer: 2023-04-08 09:42:01
avant
2658 Les gens l'ont consulté

Brève analyse du processus en cours d'exécution de Pimple (conteneur PHP)

Points de connaissances requis

Clôture

Forfaits de clôture et anonymes les fonctions ont été introduites dans PHP5.3.0.

La fermeture fait référence à :

Une fonction qui encapsule l'état environnant lors de sa création. Même si l’environnement dans lequel se situe la fermeture n’existe plus, l’état encapsulé dans la fermeture existe toujours.

Théoriquement, les fermetures et les fonctions anonymes sont des concepts différents. Mais PHP le traite comme le même concept.

En fait, les fermetures et les fonctions anonymes sont des objets déguisés en fonctions. Ce sont des instances de la classe Closure.

Les fermetures, comme les chaînes et les entiers, sont des types de valeurs de première classe.

Créer une fermeture :

<?php
$closure = function ($name) {
    return &#39;Hello &#39; . $name;
};
echo $closure(&#39;nesfo&#39;);//Hello nesfo
var_dump(method_exists($closure, &#39;__invoke&#39;));//true
Copier après la connexion

La raison pour laquelle nous pouvons appeler la variable $closure est que la valeur de cette variable est une fermeture et que l'objet de fermeture implémente __invoke()Méthode magique. Tant qu'il y a () après le nom de la variable, PHP trouvera et appellera la méthode __invoke().

Habituellement, les fermetures PHP sont utilisées comme rappels de fonctions. Les méthodes

array_map(), preg_replace_callback() utilisent toutes des fonctions de rappel. C'est le meilleur moment pour utiliser les fermetures !

Par exemple :

<?php
$numbersPlusOne = array_map(function ($number) {
    return $number + 1;
}, [1, 2, 3]);
print_r($numbersPlusOne);
Copier après la connexion

obtient le résultat :

[2, 3, 4]
Copier après la connexion

Avant les fermetures, vous ne pouviez créer que des fonctions nommées individuellement, puis référencer cette fonction par son nom. En faisant cela, l'exécution du code sera légèrement plus lente et l'implémentation du rappel sera isolée du scénario d'utilisation.

<?php
function incrementNum ($number) {
    return $number + 1;
}
$numbersPlusOne = array_map(&#39;incrementNum&#39;, [1, 2, 3]);
print_r($numbersPlusOne);
Copier après la connexion

SPL

ArrayAccess

implémente l'interface ArrayAccess, qui permet aux objets de fonctionner comme des tableaux. L'interface ArrayAccess contient quatre méthodes qui doivent être implémentées :

interface ArrayAccess {
    //检查一个偏移位置是否存在 
    public mixed offsetExists ( mixed $offset  );
    
    //获取一个偏移位置的值 
    public mixed offsetGet( mixed $offset  );
    
    //设置一个偏移位置的值 
    public mixed offsetSet ( mixed $offset  );
    
    //复位一个偏移位置的值 
    public mixed offsetUnset  ( mixed $offset  );
}
Copier après la connexion

SplObjectStorage

SplObjectStorageLa classe implémente une carte avec des objets comme clés ou une collection d'objets ( Si vous ignorez les données correspondant à l'objet comme clé) cette structure de données. Une instance de cette classe ressemble beaucoup à un tableau, mais les objets qu’elle stocke sont tous uniques. Une autre fonctionnalité de cette classe est que vous pouvez directement supprimer l'objet spécifié sans parcourir ni rechercher dans l'intégralité de la collection.

::class Syntaxe

Parce que ::class représente une chaîne. L'avantage d'utiliser ::class est que vous pouvez le renommer directement en class dans l'IDE, puis l'IDE gérera automatiquement les références pertinentes.

En même temps, lorsque PHP exécute le code concerné, il ne chargera pas d'abord la classe concernée.

De même, l'inspection automatisée du code inspect peut également identifier correctement les classes.

Une brève analyse du processus du conteneur Pimple

Pimpl est un conteneur populaire dans la communauté PHP. Il n'y a pas beaucoup de code, voir

https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php pour plus de détails.

Notre application peut être développée sur la base de Pimple :

namespace EasyWeChat\Foundation;
use Pimple\Container;
class Application extends Container
{
    /**
     * Service Providers.
     *
     * @var array
     */
    protected $providers = [
        ServiceProviders\ServerServiceProvider::class,
        ServiceProviders\UserServiceProvider::class
    ];
    /**
     * Application constructor.
     *
     * @param array $config
     */
    public function __construct($config)
    {
        parent::__construct();
        $this[&#39;config&#39;] = function () use ($config) {
            return new Config($config);
        };
        if ($this[&#39;config&#39;][&#39;debug&#39;]) {
            error_reporting(E_ALL);
        }
        $this->registerProviders();
    }
    /**
     * Add a provider.
     *
     * @param string $provider
     *
     * @return Application
     */
    public function addProvider($provider)
    {
        array_push($this->providers, $provider);
        return $this;
    }
    /**
     * Set providers.
     *
     * @param array $providers
     */
    public function setProviders(array $providers)
    {
        $this->providers = [];
        foreach ($providers as $provider) {
            $this->addProvider($provider);
        }
    }
    /**
     * Return all providers.
     *
     * @return array
     */
    public function getProviders()
    {
        return $this->providers;
    }
    /**
     * Magic get access.
     *
     * @param string $id
     *
     * @return mixed
     */
    public function __get($id)
    {
        return $this->offsetGet($id);
    }
    /**
     * Magic set access.
     *
     * @param string $id
     * @param mixed  $value
     */
    public function __set($id, $value)
    {
        $this->offsetSet($id, $value);
    }
}
Copier après la connexion

Comment utiliser notre application :

$app = new Application([]);
$user = $app->user;
Copier après la connexion

Après cela, nous pouvons utiliser la méthode de l'objet $user . Nous avons constaté qu'il n'y a pas d'attribut $this->user, mais il peut être utilisé directement. Principalement le rôle de ces deux méthodes :

public function offsetSet($id, $value){}
public function offsetGet($id){}
Copier après la connexion

Ci-dessous nous expliquerons ce que fait Pimple lors de l'exécution de ces deux lignes de code. Mais avant d’expliquer cela, examinons quelques concepts fondamentaux des conteneurs.

Fournisseur de services

Le fournisseur de services est le pont entre le conteneur et la classe d'implémentation de fonction spécifique. Les fournisseurs de services doivent implémenter l'interface ServiceProviderInterface:

namespace Pimple;
/**
 * Pimple service provider interface.
 *
 * @author  Fabien Potencier
 * @author  Dominik Zogg
 */
interface ServiceProviderInterface
{
    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $pimple A container instance
     */
    public function register(Container $pimple);
}
Copier après la connexion

Tous les fournisseurs de services doivent implémenter la méthode de registre d'interface.

Il y a 2 fournisseurs de services par défaut dans notre application :

protected $providers = [
    ServiceProviders\ServerServiceProvider::class,
    ServiceProviders\UserServiceProvider::class
];
Copier après la connexion

En prenant UserServiceProvider comme exemple, regardons son implémentation de code :

namespace EasyWeChat\Foundation\ServiceProviders;
use EasyWeChat\User\User;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
/**
 * Class UserServiceProvider.
 */
class UserServiceProvider implements ServiceProviderInterface
{
    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $pimple A container instance
     */
    public function register(Container $pimple)
    {
        $pimple[&#39;user&#39;] = function ($pimple) {
            return new User($pimple[&#39;access_token&#39;]);
        };
    }
}
Copier après la connexion

On voit que Le La méthode d'enregistrement du fournisseur de services ajoutera des attributs user au conteneur, mais ce qui est renvoyé n'est pas un objet, mais une fermeture. J'expliquerai cela plus tard.

Enregistrement des services

Nous utilisons Application dans le constructeur en $this->registerProviders(); pour enregistrer tous les prestataires de services :

private function registerProviders()
{
    foreach ($this->providers as $provider) {
        $this->register(new $provider());
    }
}
Copier après la connexion

Regardez attentivement, nous trouvons que le fournisseur de services est instancié ici et que la méthode d'enregistrement du conteneur Pimple est appelée :

public function register(ServiceProviderInterface $provider, array $values = array())
{
    $provider->register($this);
    foreach ($values as $key => $value) {
        $this[$key] = $value;
    }
    return $this;
}
Copier après la connexion

Et la méthode register du fournisseur de services est appelée ici, ce que nous avons mentionné dans la section précédente Arrivé : La méthode d'enregistrement ajoute des attributs user au conteneur, mais elle ne renvoie pas un objet, mais une fermeture.

Lorsque nous ajouterons l'attribut user au conteneur Pimple, la méthode offsetSet($id, $value) sera appelée : attribuer des valeurs aux attributs Pimple et aux clés du conteneur values respectivement :

$this->values[$id] = $value;
$this->keys[$id] = true;
Copier après la connexion

Ici, nous La classe EasyWeChatUserUsr qui fournit réellement la fonctionnalité réelle n'a pas encore été instanciée. Cependant, l'enregistrement du fournisseur de services est terminé.

Lorsque nous exécutons ici :

$user = $app->user;
Copier après la connexion

appellera offsetGet($id) et instanciera la vraie classe :

$raw = $this->values[$id];
$val = $this->values[$id] = $raw($this);
$this->raw[$id] = $raw;
$this->frozen[$id] = true;
return $val;
Copier après la connexion

$raw obtient la fermeture :

$pimple[&#39;user&#39;] = function ($pimple) {
    return new User($pimple[&#39;access_token&#39;]);
};
Copier après la connexion

$raw($this)返回的是实例化的对象User。也就是说只有实际调用才会去实例化具体的类。后面我们就可以通过$this['user']或者$this->user调用User类里的方法了。

当然,Pimple里还有很多特性值得我们去深入研究,这里不做过多讲解。

更多相关php知识,请访问php教程

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!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!