Как стать автором
Обновить

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

Время на прочтение2 мин
Количество просмотров2.1K

Задача


В общем, сложилась такая ситуация, что на предоставленном для проекта хостинге, версия 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');

Вот собственно и все. Спасибо за внимание.
Теги:
Хабы:
Всего голосов 58: ↑36 и ↓22+14
Комментарии73

Публикации

Истории

Работа

PHP программист
168 вакансий

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань