3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features
<?php function sortDump(...$mixed) { unset($_SERVER); echo '<pre>'; debug_zval_dump( (count($mixed) == 1 ? array_pop( $mixed ) : $mixed )); echo '</pre><br><br><pre>'; var_dump( (count( $mixed ) == 0 ? $GLOBALS : $mixed) ); echo '</pre><br><br><pre>'; echo "################## BACK TRACE ###################\n"; var_dump( debug_backtrace( ) ); echo '</pre>'; die(1); } trait Singleton { private $storage; // A Temporary variable for 'quick data' protected $methods = array(); // Anonymous Function Declaration protected static $getInstance; // Instance of the Container public static function __callStatic($methodName, $arguments = array()) { return self::getInstance()->Skeleton( $methodName, $arguments ); } public static function newInstance() { // Start a new instance of the class and pass any arguments $class = new \ReflectionClass( get_called_class() ); self::$getInstance = $class->newInstanceArgs( func_get_args() ); return self::$getInstance; } public static function getInstance() { // see if the class has already been called this run if (!empty(self::$getInstance)) return self::$getInstance; $calledClass = get_called_class(); // check if the object has been sterilized in the session // This will invoke the __wake up operator if (isset($_SESSION) && array_key_exists( $calledClass, $_SESSION ) && is_object( self::$getInstance = unserialize( $_SESSION[$calledClass] ))) return self::$getInstance; // Start a new instance of the class and pass any arguments $class = new \ReflectionClass( get_called_class() ); self::$getInstance = $class->newInstanceArgs( func_get_args() ); return self::$getInstance; } /** * @param null $object * @return object|null */ public static function clearInstance($object = null) { self::$getInstance = is_object( $object ) ? $object : null; if (array_key_exists( __CLASS__, $_SESSION )) unset($_SESSION[__CLASS__]); return self::$getInstance; } public function __call($methodName, $arguments = array()) { return $this->Skeleton( $methodName, $arguments ); } private function Skeleton($methodName, $arguments = array()) { // Have we used addMethod() to override an existing method if (key_exists( $methodName, $this->methods )) return (null === ($result = call_user_func_array( $this->methods[$methodName], $arguments )) ? $this : $result); // Is the method in the current scope ( public, protected, private ). // Note declaring the method as private is the only way to ensure single instancing if (method_exists( $this, $methodName )) { return (null === ($result = call_user_func_array( array($this, $methodName), $arguments )) ? $this : $result); } if (key_exists( 'closures', $GLOBALS ) && key_exists( $methodName, $GLOBALS['closures'] )) { $function = $GLOBALS['closures'][$methodName]; $this->addMethod( $methodName, $function ); return (null === ($result = call_user_func_array( $this->methods[$methodName], $arguments )) ? $this : $result); } throw new \Exception( "There is valid method or closure with the given name '$methodName' to call" ); } private function addMethod($name, $closure) { if (is_callable( $closure )): $this->methods[$name] = \Closure::bind( $closure, $this, get_called_class() ); else: // Nested to ensure Singleton returns the correct value of self throw new \Exception( "New Method Must Be A Valid Closure" ); endif; } public function __wakeup() { if (method_exists( $this, '__construct' )) self::__construct(); $object = get_object_vars( $this ); foreach ($object as $item => $value) // TODO - were really going to try and objectify everything? if(is_object( $temp = @unserialize($this->$item))) $this->$item = $temp; } // for auto class serialization add: const Singleton = true; to calling class public function __sleep() { if (!defined( 'self::Singleton' ) || !self::Singleton) return null; $object = get_object_vars( $this ); foreach ($object as $key => &$value) { if (empty($value) || empty($this->$key)) continue; // The object could be null from serialization? if (is_object( $value )) { try { $this->$key = @serialize( $value ); } catch (\Exception $e){ continue; } // Database object we need to catch the error thrown. if ($_SESSION[__CLASS__][0] != 'O') continue; } $onlyKeys[] = $key; } return (isset($onlyKeys) ? $onlyKeys : null); } public function __destruct() { // We require a sleep function to be set manually for singleton to manage utilization if (!defined( 'self::Singleton' ) || !self::Singleton) return null; try { $_SESSION[__CLASS__] = @serialize( $this ); // I was using if (__sleep != null).. but resulted in errors, this is a shitty fix ill admit } catch (\Exception $e){ unset($_SESSION[__CLASS__]); return null; }; if ($_SESSION[__CLASS__][0] != 'O') unset($_SESSION[__CLASS__]); // We only want to store objects, if } // The rest of the methods are for the sake of methods public function &__get($variable) { return $GLOBALS[$variable]; } public function __set($variable, $value) { $GLOBALS[$variable] = $value; } public function __isset($variable) { return array_key_exists( $variable, $GLOBALS ); } public function __unset($variable) { unset($GLOBALS[$variable]); } public function __invoke() { return $this->storage; } private function set($name, $value = null) { $this->storage = null; if ($value == null) { if (is_array( $name )) $this->storage = $name; else $this->storage[] = $name; } else $this->storage[$name] = $value; return $this; } private function get($variable = null) { return ($variable == null ? $this->storage : $this->{$variable}); } private function has($variable) { return isset($this->$variable); } } class stdOJB implements \ArrayAccess { use Singleton; const Singleton = true; // turns on auto caching public function __construct() { return null; } public function offsetSet($offset, $value) { if (is_null($offset)) $this->storage[] = $value; else $this->storage[$offset] = $value; } public function offsetExists($offset) { return isset($this->storage[$offset]); } public function offsetUnset($offset) { unset($this->storage[$offset]); } public function offsetGet($offset) { return isset($this->storage[$offset]) ? $this->storage[$offset] : null; } public function &__get($variable) { return $this->storage[$variable]; } public function __set($variable, $value) { $this->storage[$variable] = $value; } public function __isset($variable) { return array_key_exists( $variable, $this->storage ); } public function __unset($variable) { unset($this->storage[$variable]); } public function __destruct() { return null; } } abstract class QuickFetch { protected $db; public function fetch_into_current_class($array) { $object = get_object_vars( $this ); foreach ($array as $key => $value) if (array_key_exists( $key, $object )) $this->$key = $value; } public function fetch_as_object($sql,... $execute) { try { $stmt = $this->db->prepare( $sql ); $stmt->setFetchMode( \PDO::FETCH_CLASS, Skeleton::class ); $stmt->execute( $execute ); $stmt = $stmt->fetchAll(); // user obj return (is_array( $stmt ) && count( $stmt ) == 1 ? array_pop( $stmt ) : $stmt); } catch (\Exception $e) { sortDump( $e ); } } } class user extends QuickFetch { use Singleton; const Singleton = true; public $course; public function __construct() { $this->courseId = 3; $this->boxColor = 'black'; } private function getPublicData() { if (!empty($this->courseId) && (!is_object( $this->course ) || $this->course->course_id != $this->courseId)) $this->course = (object) ['course_id' => 3]; // $this->fetch_as_object( $sql, $id ); if (!empty($this->boxColor)) { if (!is_object( $this->course )) throw new \Error(); if (!isset($this->course->distance) || !is_object( $this->course->distance ) || $this->course->distance->distance_color != $this->boxColor) { $this->course->distance = (object) array();//$this->fetch_as_object( 'SELECT * FROM StatsCoach.golf_distance WHERE course_id = ? AND distance_color = ?', $this->courseId, $this->boxColor ); return null; } if (!is_object( $this->course->distance )) throw new \Exception(); return null; } } } user::getPublicData();
based on f5SuZ
Output for 5.6.0 - 5.6.30, hhvm-3.15.4, 7.0.0 - 7.2.0