Интересные и порой необычные свойства скрывает от документирования пятая версия PHP. Языковая конструкция self по определению служит для работы со статическими методами и свойствами классов. Но ее можно использовать и не по назначению.
Многие сталкивались с проблемой переименования класса (Забываешь переименовать конструктор, но ошибки нету и все вроде работает, но как-то кривовато). Именно чтобы решить эту проблему в PHP5 ввели стандартное имя для конструкторов __construct
Эту проблему можно еще больше облегчить, если использовать self для объявления нового экземпляра класса. Например:
Теперь за имя класса волноваться не стоит. Однако в этом случае, особой пользы от такого объявления мы не получаем.
Дальше представим себя крутыми разработчиками крутой библиотеки. И теперь все классы, для которых мы хотим использовать единственный объект должны для этого будут наследоваться от Spadar_Core_Object. Немного модифицируем код класса:
Есть и альтернативный вариант: вместо new self завести переменную $sClassName = __CLASS__; и объявить так: new $sClassName();
В PHP5 для параметров методов можно указывать тип. В том числе в качестве типа можно указывать self
В этом примере строится дерево из объектов, для этого каждому объекту передаются его дочерние, т.е. они должны быть определенного типа.
Возвращаемся к написанию гипер-библиотеки на PHP. Предположим, что в каком-то пакете информация хранится через серализацию. Для того, чтобы правильно с ней работать нам нужно проверить соответствует ли она заданному интерфейсу:
Константы классов можно использовать не только привычным способом внутри тела методов, но и немного поизвращаться с ними:
Нужно помнить:
Объявляю себя ...
Многие сталкивались с проблемой переименования класса (Забываешь переименовать конструктор, но ошибки нету и все вроде работает, но как-то кривовато). Именно чтобы решить эту проблему в PHP5 ввели стандартное имя для конструкторов __construct
Эту проблему можно еще больше облегчить, если использовать self для объявления нового экземпляра класса. Например:
class Spadar_Core_Object
{
/**
* Одиночный экземпляр класса
*
* @staticvar Spadar_Core_Object
*/
private static $oInstance;
…
/**
* Получить одиночный экземпляр класса (шаблон проектирования singleton)
*
* return Spadar_Core_Object singleton instance
*/
public static function getInstance()
{
if (!isset(self::$oInstance))
{
self::$oInstance = new self();
}
return self::$oInstance;
}
…
}
Теперь за имя класса волноваться не стоит. Однако в этом случае, особой пользы от такого объявления мы не получаем.
Дальше представим себя крутыми разработчиками крутой библиотеки. И теперь все классы, для которых мы хотим использовать единственный объект должны для этого будут наследоваться от Spadar_Core_Object. Немного модифицируем код класса:
class Spadar_Core_Object
{
/**
* Одиночные экземпляры классов наследников
*
* @staticvar array
*/
private static $aInstances = array();
…
/**
* Получить одиночный экземпляр класса-наследника (шаблон проектирования singleton)
*
* return Spadar_Core_Object singleton instance
*/
public static function getInstance()
{
if (!isset(self::$aInstances[__CLASS__]))
{
self::$aInstances[__CLASS__] = new self();
}
return self::$aInstances[__CLASS__];
}
…
}
Есть и альтернативный вариант: вместо new self завести переменную $sClassName = __CLASS__; и объявить так: new $sClassName();
Проверка типа параметров
В PHP5 для параметров методов можно указывать тип. В том числе в качестве типа можно указывать self
class Spadar_Controller_Widget extends Spadar_Core_Object
{
/**
* Сыылки на дочерние виджеты
*
* var array
*/
protected $aChildWidgets = array();
…
/**
* Добавление дочернего элемента к Виджету
*
* param Spadar_Controller_Widget $oWidget новый дочерний элемент
* return Spadar_Controller_Widget вызываемый объект для последующих операций
*/
public function addChild(self $oWidget)
{
$this->aChildWidgets[] = $oWidget;
return $this;
}
…
}
В этом примере строится дерево из объектов, для этого каждому объекту передаются его дочерние, т.е. они должны быть определенного типа.
Это я или не я?
Возвращаемся к написанию гипер-библиотеки на PHP. Предположим, что в каком-то пакете информация хранится через серализацию. Для того, чтобы правильно с ней работать нам нужно проверить соответствует ли она заданному интерфейсу:
class Spadar_Core_Object
{
…
/**
* Восстановление объекта
*
* param string $sInfo
* return Spadar_Core_Object вызываемый объект для последующих операций
*/
private function parseObject($sInfo)
{
$mInfo = $sInfo;
$mInfo = @unserialize($sInfo);
if ($mInfo instanceof self)
{
return $mInfo;
}
return $this;
}
…
}
О Константах...
Константы классов можно использовать не только привычным способом внутри тела методов, но и немного поизвращаться с ними:
class Spadar_Controller_Url extends Spadar_Core_Object
{
const PARSE_PROTOCOL = 'scheme';
const PARSE_HOST = 'host';
…
const BROWSER_ARG_PROTOCOL = self::PARSE_PROTOCOL;
/**
* Какой параметр достать из урла
*
* param string $sParam параметр для доставания из URLа
* return string значение параметра
*/
public function getParam($sParam = self::PARSE_HOST)
{
…
}
…
}
Нужно помнить:
- К константам классов-родителей можно тоже обращаться по self
- Лучше переводить в константы все известные строковые конструкции. При дебаге проекта их проще искать
- Динамически создавать константы можно будет только в PHP6.