Задача
В общем, сложилась такая ситуация, что на предоставленном для проекта хостинге, версия 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]; } }
И теперь любой наследник этого класса будет Singleton`ом.
class Test extends Singleton { public function say(){ return 'Hi Habr!'; } } echo Test::model()->say();
Такой приём возможен из-за появления новой функции get_called_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');
Вот собственно и все. Спасибо за внимание.
