![therselman@gmail.com](/assets/img/avatar_default.png)
3 changed files with 206 additions and 98 deletions
@ -1,160 +1,157 @@
@@ -1,160 +1,157 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* Collection class with dynamic members and methods |
||||
* Similar functionality to an Array or Dictionary class |
||||
* Typically holding a collection/array of Entity members |
||||
*/ |
||||
|
||||
namespace Twister; |
||||
|
||||
class Collection implements \Iterator, \Countable, \ArrayAccess |
||||
{ |
||||
protected $_ = null; |
||||
protected $members = null; |
||||
protected $methods = null; |
||||
|
||||
public function __construct(array $members = null) |
||||
public function __construct(array $members = null, array $methods = null) |
||||
{ |
||||
$this->_ =& $members; |
||||
$this->members =& $members; |
||||
$this->methods =& $methods; |
||||
} |
||||
|
||||
function &__get($key) |
||||
|
||||
/** |
||||
* Get member by id/index |
||||
* |
||||
* @param string|int $idx |
||||
* @return mixed |
||||
*/ |
||||
public function __get($idx) |
||||
{ |
||||
return $this->_[$key] ?? null; |
||||
return $this->members[$idx]; |
||||
} |
||||
function __set($key, $value) |
||||
|
||||
/** |
||||
* Set member by id/index |
||||
* |
||||
* @param string|int $idx |
||||
* @param mixed $value |
||||
* @return void |
||||
*/ |
||||
public function __set($idx, $value) |
||||
{ |
||||
return $this->_[$key] = $value; |
||||
$this->members[$idx] = $value; |
||||
} |
||||
|
||||
|
||||
function __isset($key) |
||||
function __isset($idx) |
||||
{ |
||||
return isset($this->_[$key]); |
||||
return isset($this->members[$idx]); |
||||
} |
||||
function __unset($key) |
||||
function __unset($idx) |
||||
{ |
||||
unset($this->_[$key]); |
||||
unset($this->members[$idx]); |
||||
} |
||||
|
||||
|
||||
function &all() |
||||
public function &all() |
||||
{ |
||||
return $this->_; |
||||
return $this->members; |
||||
} |
||||
function set($key, $value) // alias for __set() |
||||
public function get($name) // alias for __get() |
||||
{ |
||||
return $this->_[$key] =& $value; |
||||
return $this->members[$name]; |
||||
} |
||||
function &get($key, $default = null) // alias for __get() |
||||
public function set($name, $value) // alias for __set() |
||||
{ |
||||
return $this->_[$key] ?? $default; |
||||
return $this->members[$name] = $value; |
||||
} |
||||
function has($key) // alias for __isset() |
||||
public function has($name) // alias for __isset() |
||||
{ |
||||
return isset($this->_[$key]); |
||||
return isset($this->members[$name]); |
||||
} |
||||
function &merge($key, array $arr) // we need this function because we cannot (re)`set` the arrays to new values without unsetting the old values first! ie. __set() will fail because it already exists! |
||||
public function remove($name) // alias for __unset() |
||||
{ |
||||
// TODO: Add is_array() checks to the container, and add variable number of array inputs! |
||||
$this->_[$key] = array_merge($this->_[$key], $arr); |
||||
return $this->_[$key]; |
||||
} |
||||
function remove($key) // alias for __unset() |
||||
{ |
||||
unset($this->_[$key]); |
||||
unset($this->members[$name]); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Workaround for the `array access functions` eg. array_push($obj->toArray(), $value); |
||||
*/ |
||||
public function &toArray() |
||||
{ |
||||
return $this->members; |
||||
} |
||||
|
||||
|
||||
function &__call($method, $args) |
||||
public function __call($method, $args) |
||||
{ |
||||
if (isset($this->_[$method])) |
||||
if (is_callable($this->_[$method])) |
||||
{ |
||||
$result = call_user_func_array($this->_[$method], $args); |
||||
return $result; |
||||
} |
||||
else |
||||
return $this->_[$method]; |
||||
else |
||||
{ |
||||
if (preg_match('/^([gs]et|has|isset|unset)([A-Z_])(.*)$/', $method, $match)) |
||||
{ |
||||
$property = strtolower($match[2]). $match[3]; |
||||
switch($match[1]) |
||||
{ |
||||
case 'get': return $this->_[$property] ?? $args[0] ?? null; |
||||
case 'set': return $this->_[$property] = $args[0]; |
||||
case 'has': // fallthrough vvv alias for `isset` |
||||
case 'isset': $result = isset($this->_[$property]); return $result; |
||||
case 'unset': $result = null; unset($this->_[$property]); return $result; |
||||
} |
||||
//throw new \InvalidArgumentException("Property {$property} doesn't exist"); |
||||
} |
||||
throw new \InvalidArgumentException(__CLASS__ . "->{$method}() doesn't exist"); |
||||
} |
||||
array_unshift($args, $this); |
||||
return call_user_func_array($this->methods[$method], $args); |
||||
} |
||||
|
||||
// |
||||
// Workaround for the `array access functions` eg. array_push($obj->toArray(), 'Hello World!'); |
||||
// |
||||
public function &toArray() |
||||
public function __invoke() |
||||
{ |
||||
return $this->_; |
||||
return $this->methods['__invoke']($this); |
||||
} |
||||
public function &__invoke() |
||||
{ // TODO: What do you think about this technique? We could just leave it if we don't use it! |
||||
// Basically, we are calling an internal `__invoke` handler |
||||
// eg. $myCollection['__invoke'] = function($c) { return $c->all(); } |
||||
return $this->_['__invoke']($this); |
||||
public function setMethod($method, callable $callable) |
||||
{ |
||||
$this->methods[$method] = $callable; |
||||
return $this; |
||||
} |
||||
|
||||
// |
||||
// Iterator interface |
||||
// |
||||
|
||||
/** |
||||
* Iterator interface |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
return reset($this->_); |
||||
return reset($this->members); |
||||
} |
||||
public function current() |
||||
{ |
||||
return current($this->_); |
||||
return current($this->members); |
||||
} |
||||
public function key() |
||||
{ |
||||
return key($this->_); |
||||
return key($this->members); |
||||
} |
||||
public function next() |
||||
{ |
||||
return next($this->_); |
||||
return next($this->members); |
||||
} |
||||
public function valid() |
||||
{ |
||||
return key($this->_) !== null; |
||||
return key($this->members) !== null; |
||||
} |
||||
|
||||
|
||||
// |
||||
// Countable interface |
||||
// |
||||
/** |
||||
* Countable interface |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return count($this->_); |
||||
return count($this->members); |
||||
} |
||||
|
||||
|
||||
// |
||||
// ArrayAccess interface |
||||
// |
||||
public function offsetSet($id, $value) // eg. $obj['two'] = 'A value'; |
||||
/** |
||||
* ArrayAccess interface |
||||
*/ |
||||
public function offsetGet($idx) // eg. var_dump($obj['two']); |
||||
{ |
||||
$this->_[$id] = $value; |
||||
return $this->members[$idx]; |
||||
} |
||||
public function offsetExists($id) // eg. isset($obj['two']) |
||||
public function offsetSet($idx, $value) // eg. $obj['two'] = 'A value'; |
||||
{ |
||||
return isset($this->_[$id]); |
||||
$this->members[$idx] = $value; |
||||
} |
||||
public function offsetUnset($id) // eg. unset($obj['two']); |
||||
public function offsetExists($idx) // eg. isset($obj['two']) |
||||
{ |
||||
unset($this->_[$id]); |
||||
return isset($this->members[$idx]); |
||||
} |
||||
public function offsetGet($id) // eg. var_dump($obj['two']); |
||||
public function offsetUnset($idx) // eg. unset($obj['two']); |
||||
{ |
||||
return $this->_[$id]; |
||||
unset($this->members[$idx]); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,111 @@
@@ -0,0 +1,111 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* Entity class with dynamic properties |
||||
* Properties can include callable functions, which can `lazy load` properties, or return dynamic/complex/calculated properties |
||||
*/ |
||||
|
||||
namespace Twister; |
||||
|
||||
class Entity implements \ArrayAccess |
||||
{ |
||||
protected $properties = null; |
||||
|
||||
public function __construct(array $properties = null) |
||||
{ |
||||
$this->properties =& $properties; |
||||
} |
||||
|
||||
/** |
||||
* Get entity field/property |
||||
* |
||||
* @param string $name |
||||
* @return mixed |
||||
*/ |
||||
public function __get($name) |
||||
{ |
||||
$value = $this->properties[$name]; |
||||
return is_callable($value) ? $value($this) : $value; |
||||
} |
||||
|
||||
/** |
||||
* Set entity field/property |
||||
* |
||||
* @param string $name |
||||
* @param mixed $value |
||||
* @return void |
||||
*/ |
||||
public function __set($name, $value) |
||||
{ |
||||
$this->properties[$name] = $value; |
||||
} |
||||
|
||||
|
||||
public function __isset($name) |
||||
{ |
||||
return isset($this->properties[$name]); |
||||
} |
||||
public function __unset($name) |
||||
{ |
||||
unset($this->properties[$name]); |
||||
} |
||||
|
||||
|
||||
public function &all() |
||||
{ |
||||
return $this->properties; |
||||
} |
||||
public function get($name) // alias for __get() |
||||
{ |
||||
return $this->properties[$name]; |
||||
} |
||||
public function set($name, $value) // alias for __set() |
||||
{ |
||||
return $this->properties[$name] = $value; |
||||
} |
||||
public function has($name) // alias for __isset() |
||||
{ |
||||
return isset($this->properties[$name]); |
||||
} |
||||
public function remove($name) // alias for __unset() |
||||
{ |
||||
unset($this->properties[$name]); |
||||
} |
||||
|
||||
|
||||
public function __call($method, $args) |
||||
{ |
||||
array_unshift($args, $this); |
||||
return call_user_func_array($this->properties[$method], $args); |
||||
} |
||||
public function __invoke() |
||||
{ |
||||
return $this->properties['__invoke']($this); |
||||
} |
||||
public function setMethod($method, callable $callable) |
||||
{ |
||||
$this->properties[$method] = $callable; |
||||
return $this; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* ArrayAccess interface |
||||
*/ |
||||
public function offsetGet($name) // eg. var_dump($obj['two']); |
||||
{ |
||||
return $this->properties[$name]; |
||||
} |
||||
public function offsetSet($name, $value) // eg. $obj['two'] = 'A value'; |
||||
{ |
||||
$this->properties[$name] = $value; |
||||
} |
||||
public function offsetExists($name) // eg. isset($obj['two']) |
||||
{ |
||||
return isset($this->properties[$name]); |
||||
} |
||||
public function offsetUnset($name) // eg. unset($obj['two']); |
||||
{ |
||||
unset($this->properties[$name]); |
||||
} |
||||
} |
Loading…
Reference in new issue