Вопросы по ООП в PHP

8.42K
.
Fublin, ООП очень сложно и вто же время просто.
Собственно, всё гениальное просто.
Попробую с Лимпом развить данную темку, хоть и сам в категории "начинающие". =)
---------------------------------
Итак, поговорим о перегрузке методов. Всем, знающим пых, известно, что функции нельзя написать вот так:
function MyFunc();
function MyFunc($a);
function MyFunc($a, $b);
function MyFunc($a, $b, $c);

по причине того, что нельзя задавать одно и то же имя разным функциям. Но что делать, если очень надо принимать в функцию разные данные. То такие, то сякие.
Тут на помощь приходит ООП. Есть там такая штучка магическая, называется __call, он запускается автоматически, когда мы вызываем метод которого нет.
Если метод (он же функция, если вне класса) не инициализирован, то с помощью __call мы можем принять имя функции и её свойства и делать с ними всё, что душе угодно. Эдакое "эмулирование" перегрузки функций, что в пыхе невозможно.
Делается это так:
//Создаём класс
class name {
   //В $name придёт имя функции, а в $array все значения в формате массива
   function __call($name, $array){
   //Внутри этой функции мы уже можем делать с полученными данными всё, что захотим
  }
}

Теперь, если мы вызовем несуществующую функцию как объект, с необходимыми свойствами, то этот момент будет у нас "под контролем".
//Создаём класс
class name {
   //В $name придёт имя функции, а в $array все значения в формате массива
   function __call($name, $array){
   //Внутри этой функции мы уже можем делать с полученными данными всё, что захотим. Можем например вывести ошибку.
   echo "Функция $name не существует!!!";
  }
}
//Вызываем метод, которого нет, автоматически вызывается __call
$something->funcTiOn('Gary', '26', 'Охранник');

Метод __call можно использовать, например, для самоконтроля. Все мы человеки и можем ошибиться (особенно если делать сайт на ядре, классах и куче функций как ДжонЦМС). Очень легко запутаться или опечататься, в случае ошибочного написания какого либо метода мы узнаем где "косяк".
Так же если работает команда. В таком случае даже классы лучше использовать "абстрактные", создавать "интерфейсы".
.
L!MP, А почему с паттерном Регистри есть проблема отложенной инициализации?
А ещё нашёл статью, хотел бы услышать твоё мнение о ней, я то с паттернами не особо пока касался.

Singleton представляет собой класс со статическим интерфейсом, что делает его доступным глобально. Пожалуй, это основная идея использования «одиночки». Удобно иметь доступ к объекту класса из любой части приложения. Например, класс работы с базой данных будет очень удобен, если будет доступен глобально, но у Singleton есть еще одна особенность, которая делает его неприменимым в данном случае. Эта особенность – возможность иметь только один объект от класса реализующего шаблон Singleton. А я если наше приложение должно соединяться с двумя разными серверами БД? В таком случае одного объекта будет недостаточно, но иметь глобальный доступ к объектам все равно хочется. Вот тут нам и поможет паттерн Registry.

Пример реализации Registry
Сам по себе, Registry – этот все тот же Singleton, с тем же статическим интерфейсом. Его объект обеспечивает связь с другими объектами и делает их доступными глобально. Чтобы было понятно, о чем пойдет речь, приведу код класса, реализующего этот паттерн. Код на PHP.
class Registry
{
    /**
     * Singleton registry instance
     * @var Singleton registry instance
     */
    static private $_instance = null;
 
    /**
     * Hash table
     * @var array
     */
    private $_registry = array(); 
 
    /**
     * Get Registry instanse
     * 
     * @return Singleton registry instance
     */
    static public function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new self;
        }
 
        return self::$_instance;
    }
 
    /**
     * Save an object by key into registry
     * 
     * @param integer|string $key
     * @param object $object
     * @return void
     */
    static public function set($key, $object) {
        self::getInstance()->_registry[$key] = $object;
    }
 
    /**
     * Get an object by key from registry
     * 
     * @param integer|string $key
     * @return object
     */
    static public function get($key) {
        return self::getInstance()->_registry[$key];
    }
 
    /**
     * Private constructor
     * @return void
     */
    private function __construct() {
    }
 
    /**
     * Disallow cloning
     * @return void
     */
    private function __clone() {
    }
}


Ну и небольшой пример использования. Представим, что у нас есть некоторый класс Foo, объект которого должен быть доступен глобально, но делать из этого класса одиночку мы не можем или не хотим.
Registry::set('foo', new Foo());
Registry::get('foo')->bar();

Регистрируем объект класс Foo через статический метод Registry::set(), после чего имеем возможность получить доступ к методу Foo::bar() через статический метод реестра Registry::get().

Уверен, что если вы работали с какими-нибудь фреймворками, то не могли не встречать реализацию Registry. Так что, скорее всего, я ничего принципиально нового вам не открыл .

Плюсы

В принципе, все плюсы я уже перечислил. Глобальный доступ – это удобно. Нет необходимости плодить множество одиночек. Теперь все они в одном месте и под строгим контролем. Ну а там, где использование паттерна Singleton, ввиду ряда причин невозможно, Registry будет выходом из ситуации.

Минусы

Минусы тоже есть, куда уж без них.

Во-первых, использование глобальных объектов может привести к тому, что проект превратиться в немасштабируемый.

Во-вторых, пусть Registry, в какой-то степени, призван заменить множество «одиночек», тем не менее, он не обеспечивает наличие только одного объекта зависимого класса. Даже если в реализации Registry мы предупредим создание двух объектов оного класса, никто не запретит разработчику действовать в обход нашего реестра.

Ну а в-третьих, мы порождаем новые зависимости. Объекты зависят от реестра и от ключей реестра. Это тоже может стать причиной плохой масштабируемости проекта.


Оригинал -> здесь.

Лично я тут ничего сверх чего-то не вижу, обычный статический класс с закрытым от общего взора "полем" $_instance (если называть по тру ООП).
А зачем использовать паттерны? Чтобы не изобретать велосипед?
Наткнулся на паттерн Strategy (направлен на реализацию взаимозаменяемости алгоритмов), вот он впечатлил, лично я, будучи пока профаном в ООП, тоже замутил бы на if-else или try-catch и понаписал бы кучу кода.

А какой паттерн выбрал ты? и можно узнать, почему? Я просто скоро начну новый проект писать, где собираюсь по полной использовать ООП, и твоя "моральная" помощь не помешала бы, смотрю ты шариш.
.
SlyDeath (23.12.2011/03:49)
L!MP, А почему с паттерном Регистри есть проблема отложенной инициализации?
Проблема не в самом Registry, он и не должен ничего делать, кроме как хранить и обеспечивать доступ к данным.
Просто она (отложенная инициализация) несколько усложнена.
Нагляднее, на примере использования Registry и того же ServiceLocator`a:

class Locator
{
    private $request;
    /**
     * Возвращает объект Request
     *
     * @return object
     */

    public function getRequest()
    {
        if (empty($this->request)) {
            $this->request = new httpRequest();
        }

        return $this->request;
    }
}

// Код с Registry
// тут нам может и нафиг не нужен \httpRequest но мы должны загнать его в реестр, и если инициализация \httpRequest связана с какими-то обьёмными вычисленниями, то lazy initialization возлагается на сам класс.

\Registry::instance()->add('httpRequest', new \httpRequest);
\Registry::instance()->get('httpRequest')->getIp();

//Код с ServiceLocator
//ServiceLocator сам обеспечивает lazy initialization, инициализируя \httpRequest при первом же обращении к нему.

\Locator::instance()->getRequest()->getIp();
.
SlyDeath,
А какой паттерн выбрал ты? и можно узнать, почему?

Я уже писал тут что использую в основном Singleton, FactoryMethod и AbstractFactory (Singleton - это вобще главный паттерн php ).
Из плюсов - всё просто, как двери.
Из минусов - много хардкодинга (статич. зависимостей).
Я просто скоро начну новый проект писать, где собираюсь по полной использовать ООП и твоя "моральная" помощь не помешала бы, смотрю ты шариш.

Возьми какой-нибудь ФВ (Yii, Kohanna) и начинай новый проект
.
L!MP (23.12.2011/15:36)
Возьми какой-нибудь ФВ (Yii, Kohanna) и начинай новый проект
Вот спасибо! В ближайшее время поковыряю Yii, кажется это то, что нужно!
А у Коханы есть русское сообщество в нете? Когда всё на англицком как-то неудобно, если поджимают сроки.
Вообще кохана это исконно украинское слово, так там зовут Любимую (именно с большой буквы) женщину.
Не работал никогда ни с ФВ ни с паттернами, думаю будет очень интересно.
.
L!MP
SlyDeath, с удовольствием тебе отвечу, Я в курсе что означает кохана на украинском и все же название ФВ происходит от индейского слова которое означает быстый.
Русского сообщества не встречал, в основном инфу можно читать в блогах и на хабре, или переводить мануалы с англ. У "й" с этим делом по легче конечно.
.
SlyDeath
L!MP, Зачем обратный слэш тут "\Registry" или тут "\Locator". С этим я что-то не встречался.
И разве статичность не полезна? Для разработки в команде или для самоконтроля?
Абстракты и интерфейсы ведь не зря придуманы.
.
Зачем обратный слэш тут "\Registry" или тут "\Locator". С этим я что-то не встречался.


Это из-за использования пространств имен.
Кпримеру, у меня все контроллеры лежат в пространстве имен Controllers и соответственно при обращение к Registry внутри контроллера, php будит искать его в том же пространстве имен.
По этому используя "\" мы указываем что Registry лежит в глобальном пространстве.

И разве статичность не полезна? Для разработки в команде или для самоконтроля?


Полезна, но нужно быть осторожным. Статические зависимости приводят к вязкости кода и снижают его переносимость.
Проблема в том, что мы должы жестко прописывать имя класса SomeClass::someMethod() внутри других классов.
И когда таких зависимостей, со временем, станет много, будит очень сложно (или практически не возможно) вносить изменения которые не будут затрагивать другие классы.
.
AlkatraZ
╭∩╮ (`-`) ╭∩╮
Кстати, вот отличная статья про NameSpaces, все растолковано просто и доходчиво:
http://blog.web2.com.ua/2009/0 ... -5-3/
.
Олег, статья вроде как старенькая уже.
Сейчас ведь для разделения используется обратный слеш ("\").
Хотя, если это учесть, то в остальном вся инфа в статье актуальна.
Всего: 383