⬆️ ⬇️

Singltons version 5.3 in 5.2

Task



In general, the situation was that on the hosting provided for the project, the PHP version was 5.2, and the project itself was written under 5.3. Surely everyone who works with PHP knows that in version 5.3 it is possible to access the class name obtained using late static binding.



For example:

<?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]; } } 


And now any heir of this class will be Singleton `th.

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


Such a technique is possible due to the appearance of the new function get_called_class in version 5.3. It is clear that in earlier versions this will not work. But what if the code is already written, and the latest version of PHP is not available?



Decision



The solution is to change the hosting or install the latest version of PHP :). But for example, I had a situation that now this is impossible, and the project should work, so I had to get out.

 <?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]; } } 


As a temporary solution to the problem is fine. Well, to solve problems related to the ability to refer to a class using a variable:

 $class_name::model(); 


Replaced by:

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


That's all. Thanks for attention.


')

Source: https://habr.com/ru/post/134221/



All Articles