Pull to refresh

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

Reading time 2 min
Views 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');

Вот собственно и все. Спасибо за внимание.
Tags:
Hubs:
+14
Comments 73
Comments Comments 73

Articles