User:MaxSem

    From Wikipedia
    <?php
    /**
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License along
     * with this program; if not, write to the Free Software Foundation, Inc.,
     * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     * http://www.gnu.org/copyleft/gpl.html
     *
     * @file
     * @since 1.23
     */
    
    /**
     * Base class for generic key-value store
     */
    abstract class DataStore {
    	/**
    	 * Maximum key length. Must be enforced in all implementations to guarantee data portability
    	 */
    	const MAX_KEY_LENGTH = 255;
    
    	private static $stores = array();
    
    	/**
    	 * Default constructor, sets class properties from config array
    	 * @param array $config: Associative array of store configuration
    	 */
    	public function __construct( array $config ) {
    		foreach ( $config as $name => $value ) {
    			$this->$name = $value;
    		}
    	}
    
    	/**
    	 * Creates a store with a given name
    	 * The store must be configured in $wgDataStores
    	 *
    	 * @param string $name
    	 * @return DataStore
    	 */
    	public static function getStore( $name = 'default' ) {
    		if ( isset( self::$stores[$name] ) ) {
    			return self::$stores[$name];
    		}
    
    		global $wgDataStores;
    		wfProfileIn( __METHOD__ );
    		if ( !isset( $wgDataStores[$name] ) ) {
    			throw new MWException( "Unrecognised data store '$name'" );
    		}
    		$config = $wgDataStores[$name];
    		$store = new $config['class']( $config );
    		self::$stores[$name] = $store;
    		wfProfileOut( __METHOD__ );
    		return $store;
    	}
    
    	/**
    	 * Returns value for a given key or null if not found
    	 *
    	 * @param string|array $key: Storage key
    	 * @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
    	 * @return mixed
    	 */
    	public abstract function get( $key, $latest = false );
    
    	/**
    	 * Gets multiple values at once.
    	 * The default implementation is a slow fallback that calls get() multiple times.
    	 * Ideally, it should be overridden with something faster.
    	 *
    	 * @param array $keys: Array of keys
    	 * @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
    	 *
    	 * @return array: Associative array of key => value. If a key wasn't found, it will be omitted
    	 */
    	public function getMulti( array $keys, $latest = false ) {
    		wfProfileIn( __METHOD__ );
    		$result = array();
    		foreach ( $keys as $key ) {
    			$value = $this->get( $key, $latest );
    			if ( $value !== null ) {
    				$result[$key] = $value;
    			}
    		}
    		wfProfileOut( __METHOD__ );
    		return $result;
    	}
    
    	/**
    	 * Sets value for a given key or keys
    	 *
    	 * @param string $key
    	 * @param mixed $value
    	 */
    	public abstract function set( $key, $value );
    
    	/**
    	 * Sets multiple values at once.
    	 * The default implementation is a slow fallback that calls set() multiple times.
    	 * Ideally, it should be overridden with something faster.
    	 *
    	 * @param array $data: Associative array of key => value pairs to be set
    	 */
    	public function setMulti( array $data ) {
    		wfProfileIn( __METHOD__ );
    		foreach ( $data as $key => $value ) {
    			$this->set( $key, $value );
    		}
    		wfProfileOut( __METHOD__ );
    	}
    
    	/**
    	 * Returns all values whose keys start with a given string
    	 *
    	 * @param string $prefix
    	 * @param bool $latest: Whether a replicated or distributed store should ensure that the data returned is latest
    	 * @return Iterator
    	 */
    	public abstract function getByPrefix( $prefix, $latest = false );
    
    	/**
    	 * Deletes value with the specified key
    	 *
    	 * @param string $key
    	 */
    	public abstract function delete( $key );
    
    	/**
    	 * Deletes all values with keys matching the given key
    	 *
    	 * @param string $prefix
    	 */
    	public final function deleteByPrefix( $prefix ) {
    		if ( $prefix === '' ) {
    			throw new MWException( 'Fool-proof against deletion of everything' );
    		}
    		$this->deleteByPrefixInternal( $prefix );
    	}
    
    	/**
    	 * Deletes all values with keys starting with a given prefix
    	 * @param $prefix
    	 */
    	protected abstract function deleteByPrefixInternal( $prefix );
    
    	/**
    	 * Generates a storage key from several parts
    	 * @return string
    	 */
    	public function key( /*...*/ ) {
    		$keys = func_get_args();
    		$key = implode( ':', $keys );
    		if ( strlen( $key ) > self::MAX_KEY_LENGTH ) {
    			throw new MWException( "Key '$key' is too long" );
    		}
    		return $key;
    	}
    
    	/**
    	 * Encodes data to be stored in a format suitable for current store.
    	 * Default implementation attempts to store primitive types in a non-serialized format.
    	 *
    	 * @param mixed $data: Data to encode
    	 * @return mixed
    	 */
    	protected function encodeValue( $data ) {
    		if ( is_array( $data ) || is_object( $data ) ) {
    			return serialize( $data );
    		}
    		return $data;
    	}
    };