Skip to content

Instantly share code, notes, and snippets.

@eric1234
Created December 16, 2013 18:23
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save eric1234/7991763 to your computer and use it in GitHub Desktop.
Save eric1234/7991763 to your computer and use it in GitHub Desktop.
A null object pattern implemented in PHP
<?php
# Implements a recursive null object pattern.
#
# Implemented as a trait so any object can make it's properties use
# the null pattern without resorting to inheritance.
#
# The goal is so you can pull data off a partially populated object
# without excessive existance checks.
trait NullPattern {
# The real data we are wrapping. Since we continually return wrapped
# objects if you ever want a unwrapped object the property can be
# simply accessed
public $__value__;
function __call($name, $arguments) {
if( is_object($this->__value__) && method_exists($this->__value__, $name) )
return new NullObject(call_user_func_array(array($this->__value__, $name), $arguments));
else
return new NullObject();
}
function __get($name) {
if( is_object($this->__value__) && property_exists($this->__value__, $name) )
return new NullObject($this->__value__->$name);
else
return new NullObject();
}
function __set($name, $value) {
if( is_object($this->__value__) ) $this->__value__->$name = $value;
}
function __isset($name) {
return is_object($this->__value__) && property_exists($this->__value__, $name);
}
function __unset($name) {
if( is_object($this->__value__) ) unset($this->__value__->$name);
}
function __toString() {
if( is_array($this->__value__) )
return implode(', ', $this->__value__);
else
return (string) $this->__value__;
}
# True if the raw value is not empty
function present() {
return !empty($this->__value__);
}
# If not present will return the given default value. If present
# then returns the raw actual underlying value.
function or_default($default) {
if( $this->present() ) {
return $this->__value__;
} else {
return $default;
}
}
# Used to simulate array access when the wrapped object is a
# non-asssociative array. So:
#
# $list(5)
#
# functions like:
#
# $list[5]
#
# Can also update an array in the same way:
#
# $list(5, 'foo')
#
# works the same as:
#
# $list[5] = 'foo'
function __invoke($key) {
if( !is_array($this->__value__) ) return new NullObject();
if( func_num_args() > 1) $this->__value__[$key] = func_get_arg(1);
if( array_key_exists($key, $this->__value__) )
return new NullObject($this->__value__[$key]);
else
return new NullObject();
}
}
# A general object that uses the NullPattern trait. Make it easy to
# turn any piece of data into something that behaves with the
# NullPattern.
class NullObject {
use NullPattern;
# Constructor to wrap a value in a NullObject object
function __construct($value=null) {
if( $value ) {
if( is_assoc($value) ) $value = (object) $value;
$this->__value__ = $value;
}
}
}
if( !function_exists('is_assoc') ) {
# Copied from: http://www.php.net/manual/en/function.is-array.php#89332
function is_assoc($v) {
return is_array($v) && array_diff_key($v,array_keys(array_keys($v)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment