Maison > développement back-end > tutoriel php > Chargement paresseux et références circulaires

Chargement paresseux et références circulaires

Susan Sarandon
Libérer: 2024-12-22 01:58:10
original
260 Les gens l'ont consulté

Lazy Loading and Circular References

Table des matières

  1. Chargement paresseux
  2. Implémentation de base du chargement différé
  3. Modèle de proxy pour le chargement paresseux
  4. Gestion des références circulaires
  5. Techniques de mise en œuvre avancées
  6. Meilleures pratiques et pièges courants

Chargement paresseux

Qu’est-ce que le chargement différé ?

Le chargement différé est un modèle de conception qui diffère l'initialisation des objets jusqu'à ce qu'ils soient réellement nécessaires. Au lieu de charger tous les objets au démarrage de l'application, les objets sont chargés à la demande, ce qui peut améliorer considérablement les performances et l'utilisation de la mémoire.

Avantages clés

  1. Efficacité de la mémoire : seuls les objets nécessaires sont chargés en mémoire
  2. Chargement initial plus rapide : l'application démarre plus rapidement car tout n'est pas chargé en même temps
  3. Optimisation des ressources : les connexions à la base de données et les opérations sur les fichiers sont effectuées uniquement en cas de besoin
  4. Meilleure évolutivité : une empreinte mémoire réduite permet une meilleure mise à l'échelle des applications

Implémentation de base du chargement différé

Commençons par un exemple simple pour comprendre le concept de base :

class User {
    private ?Profile $profile = null;
    private int $id;

    public function __construct(int $id) {
        $this->id = $id;
        // Notice that Profile is not loaded here
        echo "User {$id} constructed without loading profile\n";
    }

    public function getProfile(): Profile {
        // Load profile only when requested
        if ($this->profile === null) {
            echo "Loading profile for user {$this->id}\n";
            $this->profile = new Profile($this->id);
        }
        return $this->profile;
    }
}

class Profile {
    private int $userId;
    private array $data;

    public function __construct(int $userId) {
        $this->userId = $userId;
        // Simulate database load
        $this->data = $this->loadProfileData($userId);
    }

    private function loadProfileData(int $userId): array {
        // Simulate expensive database operation
        sleep(1); // Represents database query time
        return ['name' => 'John Doe', 'email' => 'john@example.com'];
    }
}
Copier après la connexion
Copier après la connexion

Comment fonctionne cette implémentation de base

  1. Lorsqu'un objet Utilisateur est créé, seul l'ID utilisateur est stocké
  2. L'objet Profile n'est pas créé tant que getProfile() n'est pas appelé
  3. Une fois chargé, le profil est mis en cache dans la propriété $profile
  4. Les appels ultérieurs à getProfile() renvoient l'instance mise en cache

Modèle de proxy pour le chargement paresseux

Le modèle Proxy offre une approche plus sophistiquée du chargement paresseux :

interface UserInterface {
    public function getName(): string;
    public function getEmail(): string;
}

class RealUser implements UserInterface {
    private string $name;
    private string $email;
    private array $expensiveData;

    public function __construct(string $name, string $email) {
        $this->name = $name;
        $this->email = $email;
        $this->loadExpensiveData(); // Simulate heavy operation
        echo "Heavy data loaded for {$name}\n";
    }

    private function loadExpensiveData(): void {
        sleep(1); // Simulate expensive operation
        $this->expensiveData = ['some' => 'data'];
    }

    public function getName(): string {
        return $this->name;
    }

    public function getEmail(): string {
        return $this->email;
    }
}

class LazyUserProxy implements UserInterface {
    private ?RealUser $realUser = null;
    private string $name;
    private string $email;

    public function __construct(string $name, string $email) {
        // Store only the minimal data needed
        $this->name = $name;
        $this->email = $email;
        echo "Proxy created for {$name} (lightweight)\n";
    }

    private function initializeRealUser(): void {
        if ($this->realUser === null) {
            echo "Initializing real user object...\n";
            $this->realUser = new RealUser($this->name, $this->email);
        }
    }

    public function getName(): string {
        // For simple properties, we can return directly without loading the real user
        return $this->name;
    }

    public function getEmail(): string {
        // For simple properties, we can return directly without loading the real user
        return $this->email;
    }
}
Copier après la connexion
Copier après la connexion

L'implémentation du modèle de proxy

  1. L'interface utilisateur garantit que les objets réels et proxy ont la même interface
  2. RealUser contient l'implémentation lourde réelle
  3. LazyUserProxy agit comme un substitut léger
  4. Le proxy ne crée l'objet réel que lorsque cela est nécessaire
  5. Des propriétés simples peuvent être renvoyées directement depuis le proxy

Gestion des références circulaires

Les références circulaires présentent un défi particulier. Voici une solution complète :

class User {
    private ?Profile $profile = null;
    private int $id;

    public function __construct(int $id) {
        $this->id = $id;
        // Notice that Profile is not loaded here
        echo "User {$id} constructed without loading profile\n";
    }

    public function getProfile(): Profile {
        // Load profile only when requested
        if ($this->profile === null) {
            echo "Loading profile for user {$this->id}\n";
            $this->profile = new Profile($this->id);
        }
        return $this->profile;
    }
}

class Profile {
    private int $userId;
    private array $data;

    public function __construct(int $userId) {
        $this->userId = $userId;
        // Simulate database load
        $this->data = $this->loadProfileData($userId);
    }

    private function loadProfileData(int $userId): array {
        // Simulate expensive database operation
        sleep(1); // Represents database query time
        return ['name' => 'John Doe', 'email' => 'john@example.com'];
    }
}
Copier après la connexion
Copier après la connexion

Comment fonctionne la gestion des références circulaires

  1. Le LazyLoader maintient un registre d'instances et d'initialiseurs
  2. Une pile d'initialisation suit la chaîne de création d'objet
  3. Les références circulaires sont détectées à l'aide de la pile
  4. Les objets sont créés avant d'être initialisés
  5. L'initialisation se produit une fois que tous les objets requis existent
  6. La pile est toujours nettoyée, même si des erreurs surviennent

Techniques de mise en œuvre avancées

Utilisation d'attributs pour le chargement paresseux (PHP 8)

interface UserInterface {
    public function getName(): string;
    public function getEmail(): string;
}

class RealUser implements UserInterface {
    private string $name;
    private string $email;
    private array $expensiveData;

    public function __construct(string $name, string $email) {
        $this->name = $name;
        $this->email = $email;
        $this->loadExpensiveData(); // Simulate heavy operation
        echo "Heavy data loaded for {$name}\n";
    }

    private function loadExpensiveData(): void {
        sleep(1); // Simulate expensive operation
        $this->expensiveData = ['some' => 'data'];
    }

    public function getName(): string {
        return $this->name;
    }

    public function getEmail(): string {
        return $this->email;
    }
}

class LazyUserProxy implements UserInterface {
    private ?RealUser $realUser = null;
    private string $name;
    private string $email;

    public function __construct(string $name, string $email) {
        // Store only the minimal data needed
        $this->name = $name;
        $this->email = $email;
        echo "Proxy created for {$name} (lightweight)\n";
    }

    private function initializeRealUser(): void {
        if ($this->realUser === null) {
            echo "Initializing real user object...\n";
            $this->realUser = new RealUser($this->name, $this->email);
        }
    }

    public function getName(): string {
        // For simple properties, we can return directly without loading the real user
        return $this->name;
    }

    public function getEmail(): string {
        // For simple properties, we can return directly without loading the real user
        return $this->email;
    }
}
Copier après la connexion
Copier après la connexion

Meilleures pratiques et pièges courants

Meilleures pratiques

  1. Effacer les points d'initialisation : indiquez toujours clairement où se produit le chargement paresseux
  2. Gestion des erreurs : implémentez une gestion robuste des erreurs pour les échecs d'initialisation
  3. Documentation : Documentez les propriétés chargées paresseusement et leurs exigences d'initialisation
  4. Tests : testez les scénarios de chargement paresseux et impatients
  5. Surveillance des performances : surveillez l'impact du chargement paresseux sur votre application

Pièges courants

  1. Fuites de mémoire : Ne pas publier de références à des objets chargés paresseux inutilisés
  2. Dépendances circulaires : Ne gère pas correctement les références circulaires
  3. Chargement paresseux inutile : appliquer un chargement paresseux là où il n'est pas bénéfique
  4. Thread Safety : ne prend pas en compte les problèmes d'accès simultané
  5. État incohérent : ne gère pas correctement les échecs d'initialisation

Considérations relatives aux performances

Quand utiliser le chargement paresseux

  • Objets volumineux qui ne sont pas toujours nécessaires
  • Objets dont la création nécessite des opérations coûteuses
  • Objets qui pourraient ne pas être utilisés dans chaque demande
  • Collections d'objets dont seul un sous-ensemble est généralement utilisé

Quand ne pas utiliser le chargement paresseux

  • Objets petits et légers
  • Des objets presque toujours nécessaires
  • Objets dont le coût d'initialisation est minime
  • Cas où la complexité du chargement paresseux l'emporte sur les avantages

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!

source:dev.to
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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal