Last active
November 4, 2015 19:11
-
-
Save cmattoon/0af8722ee10fddd07b12 to your computer and use it in GitHub Desktop.
PHP Base Object
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
ini_set('display_errors', true); | |
error_reporting(E_ALL); | |
class NotImplementedException extends BadMethodCallException { | |
public function __construct($message = null, $code = 0, $previous = null) { | |
parent::__construct($message, $code, $previous); | |
$this->message = "Method '{$message}' not implemented"; | |
} | |
} | |
/** | |
* Object base class. | |
* ================== | |
* | |
* Provides the following features: | |
* Assume all classes instantiated extend Object. | |
* | |
* @example: A dependency-injection system (via __invoke) | |
* class User extends Object { | |
* public function getSomeData() { | |
* $db = $this->_getDI('DB'); | |
* ... | |
* } | |
* } | |
* ...Somewhere else: | |
* $db = new DB(); | |
* $user = new User(); | |
* $user($db); // $user->_DIwhitelist['DB'] = $db; | |
* | |
* @example: Automagic setter/getter: | |
* $foo->afsdd = true; // $foo->_attrs['afsdd'] = true; | |
* | |
* @example: Read-only "constant" attributes: | |
* // Returns NULL by default | |
* $foo->getConst('MAX_COUNT'); | |
* | |
* // Returns the value of $foo->_const['REDIS_SERVER'], or 172.21.10.2 | |
* $foo->getConst('REDIS_SERVER', 'http://172.21.10.2'); | |
* | |
* // Optionally sets the value to the default if allowed: | |
* $foo->getConst('WAS_DEFINED', false, true); | |
*/ | |
class Object { | |
/** | |
* Automagical properties. | |
* @var array<str, mixed> | |
*/ | |
protected $_attrs = array(); | |
/** | |
* An array of allowed class names. | |
* @var array<str> | |
*/ | |
protected $_DIwhitelist = array(); | |
/** | |
* A container for injected objects. | |
* | |
* @var array<str, obj> $_DI | |
*/ | |
protected $_DI = array(); | |
/** | |
* A static container for dependencies. | |
* @var array<str, obj> $_SDI | |
*/ | |
protected static $_SDI = array(); | |
/** | |
* An array of "constants" that rely on access via the | |
* 'getConst()' method. | |
*/ | |
protected $_const = array(); | |
/** | |
* Constructor. | |
* | |
* @param string $name A name for debugging. | |
*/ | |
public function __construct($name) { | |
$this->name = $name; | |
echo "<div> Created Object ({$name}) </div>\n"; | |
} | |
/** | |
* The __invoke method is called when an object is used as a function. | |
* | |
* $foo = new Object(); | |
* is_callable($foo) === True | |
* $foo($args) | |
* | |
* | |
*/ | |
public function __invoke() { | |
$argv = func_get_args(); | |
$argc = sizeof(func_get_args()); | |
if ($argc === 1 && is_object($argv[0])) { | |
$this->_inject($argv[0]); }} | |
/** | |
* __toString | |
*/ | |
public function __toString() { | |
return "instanceOf Object(name={$this->name})";} | |
/** | |
* Throw an exception if method isn't found | |
* @throws NotImplementedException | |
*/ | |
public function __call($name, $args) { | |
throw new NotImplementedException($name); } | |
/** | |
* Throw an exception if method isn't found | |
* @throws NotImplementedException | |
*/ | |
public static function __callStatic($name, $args) { | |
throw new NotImplementedException($name); } | |
/** | |
* Getter | |
*/ | |
public function __get($name) { | |
$result = null; | |
if (array_key_exists($name, $this->_attrs)) { | |
$result = $this->_attrs[$name]; } | |
return $result; } | |
/** | |
* Setter | |
*/ | |
public function __set($name, $value) { | |
$this->_attrs[$name] = $value; | |
} | |
/** | |
* For calling isset() or empty() on inaccessible properties. | |
*/ | |
public function __isset($name) { | |
return (array_key_exists($name, $this->_attrs)); | |
} | |
/** | |
* Nope. | |
*/ | |
public function __unset($name) { | |
return false; | |
} | |
/** | |
* A 'constant' feature, which implements read-only attributes. | |
* If $set is true, the constant will be set to the first default | |
* value it finds, if it is undefined. This solidifies undefined | |
* "constants" as being equal to NULL (or whatever the default value | |
* was). This is good for sane defaults (getConst('DBUSER', 'root', true)) | |
* but might not always be desired. | |
* | |
* @param string $name The name of the "constant" to get. | |
* @param mixed $default (default: null) The value to return if undefined. | |
* @param bool $set Whether or not to define the const if it's undefined. | |
* @return The value of the constant, or $default. | |
*/ | |
final public function getConst($name, $default=null, $set=false) { | |
if (array_key_exists($name, $this->_const)) | |
return $this->_const[$name]; | |
if ($set) | |
$this->_const[$name] = $default; | |
return $default; } | |
/** | |
* Decides if an object should be allowed to be a dependency. | |
* If so, adds to $this->_DI or static::$_SDI. | |
* | |
* The return value is one of: | |
* true - The object has been stored. | |
* false - The object was not allowed. | |
* null - The object wasn't an object. | |
* | |
* @param object $object An object. | |
* @param bool $static (default: false) Is this a static dependency? | |
* @return mixed (true|false|null) | |
*/ | |
protected function _inject($object, $static=false) { | |
if (is_object($object)) { | |
$class_name = get_class($object); | |
if ($this->_checkDI($class_name, $static)) { | |
if ($static) { | |
static::$_SDI[ $class_name ] = $object; } | |
else { | |
$this->_DI[ $class_name ] = $object; } | |
return true; } | |
return false; } | |
return null; } | |
/** | |
* Checks if the class of the dependency to be injected is allowed. | |
* No "read/write" context exists - just boolean "Is this actually a | |
* dependency of this class?" | |
* | |
* If $this->_DIwhitelist is empty, | |
* | |
* @param string $class_name The name of the class | |
* @param bool $static (default: false) If true, searches static DI array | |
* @param bool $count (default: true) Whether to consider the size of | |
* the whitelist when determining if the object is | |
* allowed. | |
* @return bool Whether it's permissible for this class to use the object. | |
*/ | |
final protected function _checkDI($class_name, $static=false, $count=true) { | |
if ($static) { | |
return ((bool)(($count) ? count(static::$_SDIwhitelist) : true) && | |
in_array($class_name, array_keys(static::$_SDI)));} | |
return ((bool)(($count) ? count($this->_DIwhitelist) : true) && | |
in_array($class_name, array_keys($this->_DIwhitelist)));} | |
/** | |
* Retrieves a dependency that is 1) allowed and 2) has (hopefully) been | |
* instantiated. Use this in your classes: | |
* | |
* $this->_db = $this->_getDI('MySQL', true); | |
* | |
* The default behavior is to return NULL | |
* @param string $class_name The class name to retrieve. | |
* @param bool $static (default: false) Get from static store? | |
* @param bool $throw (default: false) Throw an exception if something | |
* goes wrong, or just return NULL? | |
* @throws NotImplementedException If no object can be returned. | |
* @return $$class_name, or null. | |
*/ | |
final protected function _getDI($class_name, $static=false, $throw=true) { | |
if ($this->_checkDI($class_name, $static)) { | |
if ($static === true) { | |
return static::$_SDI[ $class_name ]; } | |
return $this->_DI[ $class_name ]; } | |
if ($throw) { | |
throw new NotImplementedException($class_name); } | |
return null; } | |
} | |
class Foo extends Object {} | |
class Bar extends Object {} | |
$foo = new Foo('MyFoo'); | |
$bar = new Bar('MyBar'); | |
$foo($bar); | |
var_dump($foo); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment