Lazy методы класса загрузки в PHP

У меня есть класс с несколькими довольно большими методами. В этом случае основное и самое общее состояние большинства функций не требуется, поэтому мне было интересно, есть ли способ ленивой загрузки только частей класса. Эти методы должны иметь доступ к частным/защищенным членам, поэтому было бы идеально, если бы эти методы были родными для класса, однако при поиске других решений я столкнулся с этим в котором обсуждается использование частных членов в обратных вызовах, которые будут работоспособным решением (я бы использовал отдельные классы, которые содержат функцию, которая вызывает обратный вызов и ленивую загрузку этого класса). Это был 2009 год, и если эта функциональность была удалена в более поздних версиях PHP, я не знаю, но она, похоже, не работает здесь с 5.3.5

Есть ли способ сделать это, или у вас есть предложения по другим шаблонам, над которыми я должен смотреть?

Спасибо.


Ничего себе! Спасибо за ответы на все вопросы. Я думаю, что многие из вас считают, что это вероятная преждевременная оптимизация, или, что еще хуже, оптимизация вообще не очень эффективна, и я буду делать профилирование, чтобы проверить, что любое решение, на котором я рассчитываю, на самом деле не помогает. ... Теперь читать и переваривать все свои мысли должным образом. Еще раз спасибо.

Ответ 1

Начиная с PHP 5.4 вы можете (повторно) связывать анонимные функции и закрытие:

<?php

class Foo
{
    private $bar = 1;
}

$getBar = function() { return $this->bar; };

$foo = new Foo;
$foo->getBar = $getBar->bindTo($foo, $foo);

echo call_user_func($foo->getBar); // prints "1"

См. https://wiki.php.net/rfc/closures/object-extension для обсуждения реализации Closure и потенциальных ошибок.

В общем, если вы обнаружите, что ваш класс имеет много длинных методов, попробуйте разбить их на более мелкие куски. Опишите, что делают методы на простом английском языке. Для каждого "и" создайте новый метод и переместите код там.

Также рассмотрите различные свойства этого класса. Если некоторые из них идут концептуально вместе, подумайте о том, чтобы превратить их в свой собственный объект. Перемещайте любые методы доступа к этим свойствам для нового объекта для сцепления.

Я также несколько сомневаюсь в ваших мотивах к желанию "ленивой загрузки" методов в класс. У вас нет возможности выполнять их, даже если вы их не используете. Если это для оптимизации производительности, вы, вероятно, приближаетесь к ней с неправильного конца.

Другим вариантом было бы использовать Traits или, что еще проще, Composition.

Ответ 2

Решения обратного вызова выглядят очень уродливо.
Вы можете использовать шаблон композиции и автозагрузку:

class MyClass
{

protected $logger;

function SomeFunction($arg)
{
    $this->Logger()->write($arg);
}

function Logger()
{
    if (empty($this->logger)) $this->Logger = new Logger(); //lazy initialization of method
    return $this->logger;
}

}

Но, я должен сказать, что все это просто микро-оптимизация, не тратьте свое время. Время создания нового объекта и автозагрузки другого файла (с использованием диска) будет больше, чем простая инициализация объекта с помощью "больших" методов.

Ответ 3

Я не знаю (эффективный) способ загрузки только частей класса.

Я думаю, вам нужно будет разделить методы класса на подклассы и использовать автозагрузку для их загрузки.

Как только вы это сделаете, вы можете подумать о том, чтобы сделать что-то вроде этого:

class myMainClass
 {

   function bigFatMethod($argument, $argument2)
    {
      return mySubClass::bigFatMethod($this, $argument, $argument2); 
      // (pass $this if necessary)
    }
 }  

Это сохранит bigFatMethod() вызываемый внутри myMainClass, но внутренне, потому что вы используете автозагрузку, необходимый код загружается только тогда, когда на самом деле вызывается bigFatMethod().

Очевидно, вам нужно будет переписать bigFatMethod(), чтобы его можно было вызвать статически, а вместо доступа к $this вам нужно было бы получить доступ к объекту, переданному в его первом параметре (которому вы передаете $this в родительский класс).

Я никогда не делал этого сам - я хотел бы разделить класс на подклассы и разослать их отдельно - но я не вижу огромного недостатка в том, чтобы делать это таким образом.

Если бы вы хотели, вы могли бы даже абстрагироваться bigFatMethod() с помощью __call() магического метода, который будет искать, какой подкласс он должен load, выполняет метод и возвращает результат.

Ответ 4

Ваш класс, вероятно, пытается сделать слишком много. Я бы предложил попытаться разделить его на отдельные службы. Затем вы можете использовать контейнер для инъекций зависимостей (например, Pimple), чтобы лениво загружать только те службы, которые фактически используются.

Я бы посоветовал не злоупотреблять наследованием. Вместо этого вы должны использовать композицию над наследованием. Это делает вашу конструкцию более чистой и вашу базу кода более удобной.

Ответ 5

<?php
class BigClass
{
  public function lazy()
  {
    return include 'lazy.func.php';
  }
}

Это должно работать и удовлетворять вашим требованиям. Я не очень много думал о каких-либо побочных эффектах, которые могут иметь.

Ответ 6

загрузить только часть класса - это просто невозможно. Когда вы делаете новый экземпляр класса, он инициализирует весь класс и, следовательно, нет ленивой загрузки функции, которая вам нужна только

Ответ 7

Вы можете написать базовый класс, который включает в себя все основные функции, а затем использовать наследование для постепенного добавления более специализированных функций и использовать только наследующие классы там, где это необходимо.

Наследование объектов PHP.

Ответ 8

Вы можете использовать метод магического класса __get для динамического загрузки свойств или магического метода __call для делегирования другим классам/методам. Это потрясающе, когда вам нужно инициализировать свойства или методы и т.д. Только при их доступе.

Как ни странно, я недавно написал об этом блоге, потому что мне нужен был он в огромном классе в одном из моих проектов. Это немного связано, но я попытался объяснить это просто. Это может дать вам несколько указателей.

http://www.kalekold.net/index.php?post=16

http://php.net/manual/en/language.oop5.magic.php