1. Konzept
Lazy Load: ein Objekt, das zwar nicht alle erforderlichen Daten enthält, aber weiß, wie es die Daten erhält.
Lazy Loading scheint sehr einfach zu sein. Es besteht darin, die Daten bei Bedarf aus der Datenbank abzurufen, um den Verbrauch der Datenbank zu reduzieren. Aber es sind immer noch viele Tricks dabei.
2. Lazy Loading implementieren
Es gibt vier Hauptmethoden zum Implementieren von Lazy Load: verzögerte Initialisierung, virtueller Proxy, Werthalter und Ghosting.
(1) Verzögerte Initialisierung (Lazy Initialization)
1.1 Konzept
Dies ist die einfachste Methode. Dies bedeutet, dass Sie bei jedem Zugriff auf ein Attributfeld zunächst prüfen müssen, ob das Feld leer ist. Wenn es leer ist, ermitteln Sie den Wert dieses Felds. Dadurch muss sichergestellt werden, dass jeglicher Zugriff auf dieses Feld, auch aus der Klasse heraus, über die Erfassungsmethode erfolgen muss.
class Supplier{ private $products; public function getProducts(){ if($products == null) $products = $Product->findForSupplier(); return $products; } }
1.3 Verwendungszweck
Erwägen Sie die Verwendung von Lazy Loading nur, wenn die Domäne zusätzlichen Datenbankzugriff erfordert.
erfordert zusätzliche Aufrufe und die bei Verwendung des Hauptobjekts aufgerufenen Daten werden nicht verwendet.
Am besten geeignet für Aktivitätsaufzeichnungen, Tabellendateneinträge und Zeilendateneinträge.
(2) Virtueller Proxy (virtueller Proxy)
2.1 Konzept
ist im Wesentlichen ein Objekt, enthält nichts, nur wenn es ein ist Beim Aufruf der Methode lädt sie das entsprechende Objekt aus der Datenbank.
Einfach ausgedrückt handelt es sich um ein Proxy-Objekt eines Objekts. Das Objekt wird nicht während der Initialisierung geladen. Es wird nur geladen, wenn das Proxy-Objekt aufgerufen wird.
/** * 虚代理,只有在被访问成员时才调用闭包函数生成目标对象。 */ class VirtualProxy { private $holder = null; private $loader = null; /** * @param Closure $loader 生成被代理对象的闭包函数 */ public function __construct(Closure $loader) { $this->loader = $loader; } /** * 代理成员方法的调用 * * @param string $method * @param array $arguments * @throws BadMethodCallException * @return mixed */ public function __call($method, array $arguments = null) { $this->check(); if (!method_exists($this->holder, $method)) { throw new BadMethodCallException(); } return call_user_func_array( array(&$this->holder, $method), $arguments); } /** * 代理成员属性的读取 * * @param string $property * @throws ErrorException * @return mixed */ public function __get($property) { $this->check(); if (!isset($this->holder->$property)) { throw new ErrorException(); } return $this->holder->$property; } /** * 代理成员属性的赋值 * * @param string $property * @param mixed $value */ public function __set($property, $value) { $this->check(); $this->holder->$property = $value; } /** * 检查是否已经存在被代理对象,不存在则生成。 */ private function check() { if (null == $this->holder) { $loader = $this->loader; $this->holder = $loader(); } } } // 测试 $v = new VirtualProxy(function(){ echo 'Now, Loading', "\n"; $a = new ArrayObject(range(1,100)); $a->abc = 'a'; // 实际使用中,这里调用的是 DataMapper 的 findXXX 方法 // 返回的是领域对象集合 return $a; }); // 代理对象直接当作原对象访问 // 而此时构造方法传入的 callback 函数才被调用 // 从而实现加载对象操作的延迟 echo $v->abc . $v->offsetGet(50);
(3) Werthalter (Werthalter)
3.1 Konzept
Ein Objekt, das zum Umhüllen eines anderen Objekts verwendet wird, Ein Werthalter Auf ihn kann zugegriffen werden, um seinen Wert abzurufen. Allerdings liest er nur beim ersten Zugriff auf den Werthalter tatsächlich Daten aus der Datenbank.
(4) Ghost
4.1 Konzept
Ein reales Objekt im Teilzustand. Wenn das Objekt aus der Datenbank geladen wird, enthält es nur seine ID. Bei jedem Zugriff auf eine Domain wird der vollständige Status geladen. Stellen Sie sich einen Geist als ein Objekt vor, bei dem jedes seiner Felder auf einmal langsam initialisiert wird, oder als einen virtuellen Proxy, bei dem das Objekt selbst sein virtueller Proxy ist.
//继承要加载的对象 class DeferredEventCollection extends EventCollection { private $stmt; private $valueArray; private $run=false;//标识当前加载状态 //构造方法,不真正获取数据,只包含其$valueArray(ID) function __construct( Mapper $mapper, \PDOStatement $stmt_handle,array $valueArray ) { parent::__construct( null, $mapper ); $this->stmt = $stmt_handle; $this->valueArray = $valueArray; } //加载完全状态 function notifyAccess() { if ( ! $this->run ) { $this->stmt->execute( $this->valueArray ); $this->raw = $this->stmt->fetchAll(); $this->total = count( $this->raw ); } $this->run=true; } }
3. Risiken eines verzögerten Ladens
1. Wenn Sie Ghosting verwenden möchten, müssen Sie wissen, welche Art von Ghost Sie erstellen möchten. Dies ist oft schwer zu erkennen, wenn die Daten nicht korrekt geladen werden. Virtuelle Proxys leiden in statisch typisierten Sprachen unter dem gleichen Problem.
2. Ein verzögertes Laden kann leicht zu mehr Datenbankzugriffen als erforderlich führen. Alias im Buch „Fluktuationsbelastung“. Verwenden Sie beispielsweise Lazy Loading, um eine Sammlung zu füllen, und greifen Sie dann jeweils nur auf ein Element zu. Auf diese Weise wird bei jedem Zugriff auf ein Objekt auf die Datenbank zugegriffen, anstatt alle benötigten Objekte auf einmal auszulesen. Diese Lademethode beeinträchtigt die Leistung des Systems erheblich. Anstatt verzögert geladene Sammlungen zu verwenden, können Sie natürlich auch die Klassensammlung selbst verzögert laden, indem Sie beim Laden der Klassensammlung den gesamten Inhalt auf einmal laden.
4. Zusammenfassung
Lazy Loading eignet sich sehr gut für aspektorientierte Programmierung (AOP). Der Lazy-Loading-Vorgang kann in einem separaten Aspekt platziert werden, sodass die Lazy-Loading-Strategie unabhängig geändert werden kann und Domänenentwickler sich nicht mit Lazy-Loading-Problemen befassen müssen.
Lazy Loading ist eine gute Praxis, unabhängig davon, ob Sie Lazy Loading-Code explizit in Domänenklassen hinzufügen oder nicht. Der Vorteil der Verwendung eines Sammlungsobjekts anstelle eines Arrays besteht neben der Typsicherheit darin, dass Sie Lazy Loading verwenden können.