我一直在研究用于PHP的 immutable 对象。人们可以通过调整单身模式并轻松地使用魔术方法来做到这一点,但我在这里有一些特定的需求。
1。在任何情况下,引用都不会返回包含的值。
2。如果包含的数据是一个数组(很可能是json_decode()
加载的大型树),那么必须能够使用搜索字符串搜索密钥
例如:
$thing = $foo->get( 'go.get.the.thingy.at.this.level' );
......将返回:
$foo->_data['go']['get']['the']['thingy']['at']['this']['level']
第3。沿着包含数组寻找键的步骤,使用引用 - 不副本。
这意味着我会尽量避免使用foreach()
来电。如果你不明白我的意思(或理解为什么)这是一个问题),在PHP中:
foreach()
不会处理您正在迭代的对象。foreach()
适用于正在迭代的对象的副本。 我在这里有一些shell(除了一些小的语法问题),但我想看看是否可以提高效率,或者是否有更好的技巧来完成相同的任务
class ProperlyProtectedObject {
// PUBLIC STUFF
/// Initializes the singelton and returns a reference -- or cowardly returns a null.
public static function init( $value ) {
if( true === empty( self::$_self ) ) { // empty returns true if 0, false, null, or not set
if( false === isset( $value ) ) { // isset returns true if not set or null.
return null; // ...you idjit!
}
self::$_data = new ProperlyProtectedObject( $value );
}
return & self::$_self;
}
/// invoke ( php > =5.3 ): default
public function __invoke( $var ) {
return $this->get( $var );
}
public function __call( $f, $args ) {
return $this->get( $args );
}
public function __callStatic( $f, $args ) {
return null; // idjit.
}
/// get: NEAT TRICK:
/// if you know that you are storing an array here, then you can pass a dot syntax
/// string (e.g.: foo.bar.soemthing_else.foo.0 ) and
/// -- provided that your keys don't contain dots (:-P) --you can get the value of a
/// nested array key!
/// \return <Mixed> Any value **except** NULL is the value at the depth you are looking for.
/// \return NULL this means that you.have.a.BAD.Key.string.SomeWhere
public function get( $val ) {
$copyOfThing = null;
if( true === is_array( self::$_data ) ) {
if( true === is_string( $val ) ) {
$keys = explode( '.', $val );
if( 0 < count( $keys ) {
$copyOfThing = walk( self::$_data, $keys );
}
}
}
else {
$copyOfThing = self::$_data;
}
return $copyOfThing;
}
/// set: DOES NOTHING. This object is meant to take an act of congress to delete data.
public function __set( $objProp, $value ) {
// do nothing.
// echo '<pre>DIE IN A FIRE!!!! ' . var_export( $objProp, true ) . '</pre>';
}
/// isset:
public function __isset( $objProp ) {
return ( null !== $this->get( $objProp ) ) ? true : false;
}
/// unset: DOES NOTHING.This object is meant to take an act of congress to delete data
public function __unset( $objProp ) {
// do nothing.
// echo '<pre>DIE IN A FIRE!!!! ' . var_export( $objProp, true ) . '</pre>';
}
//
// PRIVATE STUFF
//
private $_self; ///< the singleton instance
private $_data = Array(); ///< this is the data. Just the data, and only the data.
/// CTOR: Singleton!
private function __construct( $value ) {
self::$_data = $value;
}
/// CCTOR: Singletons have have no need to copy themselves
private function __clone() {
// do nothing
}
/// fetches the value from WAAAY down in the array
private function walk( Array &$arr, Array $keystack ) {
$key = array_pop( $keystack );
if( false === array_key_exists( $key, $arr ) ) {
return null;
}
if( 0 count( $keystack ) ) {
return $arr[$key];
}
else {
return walk( $arr[$key], $keystack );
}
}
}