Синглтоны Версии 5.3–5.2



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

Например:

  
  
  
  
   

<Эphp class Singleton { static $instances = Array(); private function __construct() {} private function __clone() {} private function __wakeup() {} static function model(){ $class = get_called_class(); if (!isset(self::$instances[$class])) { self::$instances[$class] = new $class(); } return self::$instances[$class]; } }

И теперь любой наследник этого класса будет Синглтон `ом.



class Test extends Singleton { public function say(){ return 'Hi Habr!'; } } echo Test::model()->say();

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

Но что, если код уже написан, а последняя версия PHP недоступна?

Решение

Решение — сменить хостинг или установить последнюю версию PHP :).

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



<Эphp if(!function_exists('get_called_class')) { function get_called_class() { $obj = false; $backtrace = debug_backtrace(); foreach($backtrace as $row){ if($row['function'] == 'call_user_func'){ $obj = explode('::', $backtrace[2]['args'][0]); $obj = $obj[0]; break; } } if(!$obj){ $backtrace = $backtrace[1]; $file = file_get_contents($backtrace["file"]); $file = explode("\n", $file); for($line = $backtrace["line"] - 1; $line > 0; $line--) { preg_match("/(?<class>\w+)::(.

*)/", trim($file[$line]), $matches); if (isset($matches["class"])){ return $matches["class"]; } } throw new Exception("Could not find"); } return $obj; } } class Singleton { static $instances = Array(); private function __construct() {} private function __clone() {} private function __wakeup() {} static function model(){ $class = get_called_class(); if (!isset(self::$instances[$class])) { self::$instances[$class] = new $class(); } return self::$instances[$class]; } }

Вполне подойдет как временное решение проблемы.

Ну и для решения проблем, связанных с возможностью обращения к классу с помощью переменной:

$class_name::model();

Заменен на:

call_user_func($class_name. '::model');

Вот и все.

Спасибо за внимание.

Теги: #php 5.3 #php 5.2 #singleton #php

Вместе с данным постом часто просматривают: