Skip to content

Instantly share code, notes, and snippets.

@jakubmikita
Last active February 19, 2019 18:11
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakubmikita/53ac8667b4411ba2d51869e1d26b3bcc to your computer and use it in GitHub Desktop.
Save jakubmikita/53ac8667b4411ba2d51869e1d26b3bcc to your computer and use it in GitHub Desktop.
WordPress global storage using filter
<?php
/**
* Storable interface
*/
interface Storable extends \ArrayAccess, \Iterator {}
<?php
/**
* Storage
*/
class Storage extends StoreAbstract {
const storage_key = 'something';
}
<?php
/**
* Store class
*/
abstract class Store implements Storable {
/**
* Iterator position
*
* @var integer
*/
private $position = 0;
/**
* Store keys
*
* @var array
*/
private $keys = [];
/**
* Gets store key
*
* @since [Next]
* @return string
*/
public static function get_storage_key() {
return 'your_prefix/' . static::storage_key;
}
/**
* Gets stored items
*
* @since [Next]
* @return array
*/
public function get_items() {
$items = (array) apply_filters( self::get_storage_key(), [] );
$this->keys = array_keys( $items );
return $items;
}
/**
* {@inheritdoc}
*
* @since [Next]
* @throws \Exception If no offset has been provided and item doesn't implements Nameable.
* @throws \Exception If item with the given key has been already added to Store.
* @param mixed $offset Offset.
* @param mixed $value Value.
* @return void
*/
public function offsetSet( $offset, $value ) {
// Check offset.
if ( empty( $offset ) ) {
throw new \Exception( 'You must provide the item offset' );
}
// Add to Store.
add_filter( self::get_storage_key(), function( $items ) use ( $offset, $value ) {
if ( isset( $items[ $offset ] ) ) {
throw new \Exception( sprintf( 'Item with key %s already exists in %s store', $offset, __CLASS__ ) );
} else {
$items[ $offset ] = $value;
}
return $items;
} );
}
/**
* {@inheritdoc}
*
* @since [Next]
* @param mixed $offset Offset.
* @return bool
*/
public function offsetExists( $offset ) {
return isset( $this->get_items()[ $offset ] );
}
/**
* {@inheritdoc}
*
* @since [Next]
* @param mixed $offset Offset.
* @return void
*/
public function offsetUnset( $offset ) {
// Removed from Store.
add_filter( self::get_storage_key(), function( $items ) use ( $offset ) {
unset( $items[ $offset ] );
return $items;
} );
}
/**
* {@inheritdoc}
*
* @since [Next]
* @param mixed $offset Offset.
* @return mixed Value or null.
*/
public function offsetGet( $offset ) {
$items = $this->get_items();
return isset( $items[ $offset ] ) ? $items[ $offset ] : null;
}
/**
* {@inheritdoc}
*
* @since [Next]
* @return void
*/
public function rewind() {
$this->position = 0;
}
/**
* {@inheritdoc}
*
* @since [Next]
* @return mixed Value.
*/
public function current() {
return $this[ $this->key() ];
}
/**
* {@inheritdoc}
*
* @since [Next]
* @return string Key.
*/
public function key() {
return $this->keys[ $this->position ];
}
/**
* {@inheritdoc}
*
* @since [Next]
* @return void
*/
public function next() {
++$this->position;
}
/**
* {@inheritdoc}
*
* @since [Next]
* @return bool
*/
public function valid() {
$this->get_items();
return isset( $this->keys[ $this->position ] );
}
}
<?php
// In some place.
$storage = new Storage();
$storage['thing'] = 'My Thing';
// In another place.
$storage = new Storage();
$storage['other'] = 'My Other Thing';
// In third place.
$storage = new Storage();
unset( $storage['other'] );
$storage['foo'] = 'Bar';
/**
* It doesn't matter if you create each object all the time, it's using the common WP filter.
*/
// You can do loops.
foreach( $storage as $key => $value ) {
}
// You can get specific items.
$storage['foo'];
// You can do whatever you'd do with an array.
print_r( $storage );
@dero
Copy link

dero commented Feb 19, 2019

@Kubitomakita This is a nice exercise in abstraction, thanks for sharing. It might be useful in passing variables to templates, for example. But a couple of observations:

  1. Even if the data is not cloned with every new Storage instance, a new object instance is created.
  2. Why not choosing to use a static array? The side effects and implications for testing seem to be identical. Is it the syntax?
<?php
function fn_that_uses_storage() {
    $array = & get_storage();
    var_dump( $array );
}

function & get_storage() : array {
    static $storage = [];
    return $storage;
}

$array = & get_storage();
$array['foo'] = 1;

fn_that_uses_storage();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment