PHP Classes

File: class/Co3/CodeGen/Enum.php

Recommend this page to a friend!
  Classes of Oliver Anan   PHP One Line Enum   class/Co3/CodeGen/Enum.php   Download  
File: class/Co3/CodeGen/Enum.php
Role: Class source
Content type: text/plain
Description: main class
Class: PHP One Line Enum
Create enumerated types from arrays of values
Author: By
Last change: removed typos
Date: 12 years ago
Size: 9,364 bytes
 

Contents

Class file image Download
<?php
namespace Co3\CodeGen;
use \
InvalidArgumentException as InvalidArgumentException;
use \
BadMethodCallException as BadMethodCallException;
/**
 * @package Co3
 * @subpackage CodeGen
 * @author Oliver Anan <oliver@ananit.de>
 */
/**
 * Base class of enumerations.
 * Service provider for generating Enumerations.
 *
 * <p>This class can generate other enum classes at runtime and provides methods to work with enums.
 * All enum classes are derived from this class.</p>
 * <p>Creation and managment are not seperated to allow the usage
 * of a protected constructor.</p>
 * <p>Creating a new enumeration involves craeting the source code and one instance
 * for each member.</p>
 * <p><b>Manually deriving from this class will not work</b>.</p>
 * <p>Supports type hinting
 * <code>
 * //create the enumearion 'Direction'
 * Enum::create('Direction',array('Up','Down','Left','Right'));
 *
 * function move(Direction $dir,$distance){
 * //code
 * }
 * </code></p>
 * <p>implements __toString()</p>
 * @author Oliver Anan <oliver@ananit.de>
 * @version 1.0
 * @since 0.1
 * @copyright 2011 oliver anan
 * @license LGPL 3 http://www.gnu.org/licenses/lgpl.html
 */
class Enum{
   
//------ STATIC ------//
   
private static $_members = array();
    private static
$_arrays = array();
   
   
/**
     * Create a new enumeration class.
     *
     * <p>if the class name contains a \ character the class will be generated in a namespace.
     * Everything before the last \ is considered as namespace</p>
     * <p>All values of the $members array must be valid php identifiers.
     * Values o the $members array must not be PHP keywords.
     * The keys of the $members array are preserved unless $baseTwoKeysm is true</p>
     * <code>
     * //create the enumearion 'Direction' in the namespace 'My\Namespace'
     * Enum::create('My\Namespae\Direction',array('Up','Down','Left','Right'));
     * </code>
     * @param string $name the name of the class including the namespace
     * @param array $members an array containng all memebers of the enumeration.
     * The keys are preserved unless baseTwoKeys is true.
     * @param boolean $baseTwoKeys If this is true all keys will be replaced with powers of 2.
     * @return void;
     * @static
     * @throws \InvalidArgumentException
     * @throws Co3\Exception\FormatException (Only if class is available)
     * @access public
     */
   
public static function create($name, $members,$baseTwoKeys=false){
       
$code = self::generateSourceCode($name,$members);
        eval(
$code);
       
//create instances
       
self::$_arrays[$name] = array();
       
self::$_members[$name] = array();
        if(
$baseTwoKeys){
           
$i = 0;
        }
        foreach(
$members as $key => $member){
            if(
$baseTwoKeys){
               
$key = pow(2,$i++);
            }
           
$instance = new $name($key,$member);
           
self::$_members[$name][$member] = $instance;
           
self::$_arrays[$name][$key] = $instance;
        }
    }
   
/**
     * get an array with all instances of this enumeration.
     * @return array
     * @access public
     * @static
     * @throws \BadMethodCallException
     */
   
public static function toArray(){
       
$calledClass = get_called_class();
        if(
$calledClass==__CLASS__){
            throw new
BadMethodCallException(__CLASS__ . '::' . __METHOD__ . ' may only be called from deriver classes.');
        }
        return
self::$_arrays[get_called_class()];
    }
   
   
/**
     * create the php source code for an enum class
     *
     * @param $name the name o the new class including the namespace.
     * @param $members
     * @return string
     * @access private
     * @static
     * @throws \InvalidArgumentException
     * @throws Co3\Exception\FormatException (Only if class is available)
     */
   
private static function generateSourceCode($name,$members){
               
$code = "";
       
//remove leading '\'
       
$name = ltrim($name,'\\');
       
$parts = explode('\\',$name);
       
//validate class name (including namespace)
       
foreach($parts as $part){
            if(!
self::isValidIdentifier($part)){
                   
$message = "Invalid class/namespace name '{$className}'";
                    if(
class_exists('Co3\Exception\FormatException',true)){
                        throw new
Co3\Exception\FormatException($message);
                    } else {
                        throw new
InvalidArgumentException($message);
                    }
            }
        }
       
$className = array_pop($parts);;
       
$namespace = implode('\\',$parts);
       
//create source code
       
if($namespace){
           
$code .= "namespace {$namespace};\n";
        }
       
$code .= "final class {$className} extends \\" . __CLASS__ . "{\n";
        foreach(
$members as $key => $member){
            if(!
self::isValidIdentifier($member)){
               
$message = "Invalid member name '{$member}' at index {$key}.";
                if(
class_exists('Co3\Exception\FormatException')){
                    throw new
Co3\Exception\FormatException($message);
                } else {
                    throw new
InvalidArgumentException($message);
                }
            }
           
$code .= "const {$member} = '{$member}';\n";
        }
       
$code .= "}";
        return
$code;
    }
   
   
/**
     * Get an instance of the called enum class.
     *
     * <p>Return an instance of the called class if there is an instance
     * with an name that equals $name.</p>
     * <p>Enumeations define class constants for every member.
     * You can use the name or the constant to get an instance</p>
     * <p>Subsequent calls to get with the same $name will return the same instance</p>
     * <code>
     * Enum::create('Direction',array('Up','Down','Left','Right'));
     * $up = Direction::get(Direction::Up);
     * //is the same as
     * $upToo = Direction::get('Up');
     * //There is just one instance for every member.
     * $up === $upToo //true
     * </code>
     * <p>If there is no matching instance a InvalidArgumentException is thrown.</p>
     * @param string $name the name of the instance.
     * @return unknown_type an instance of the called class
     * @access public
     * @static
     * @throws \BadMethodCallException
     */
   
public static function get($name){
           
$calledClass = get_called_class();
        if(
$calledClass==__CLASS__){
            throw new
BadMethodCallException(__CLASS__ . '::' . __METHOD__ . ' may only br called from deriver classes.');
        }
        if (
$calledClass::isMember($name)){
            return
Enum::$_members[$calledClass][$name];
        } else {
            throw new
InvalidArgumentException("{$name} is no valid member of {$calledClass}");
        }
    }
   
   
/**
     * Get an instance of the called enum class.
     *
     * Return an instance of the called class if there is an instance
     * with an key that equals $key.
     * If there is no matching instance a InvalidArgumentException is thrown.
     * @param $key the key of the instance.
     * @access public
     * @static
     * @return unknown_type an instance o the called class
     * @throws \BadMethodCallException
     */
   
public static function getByKey($key){
       
$calledClass = get_called_class();
        if(
$calledClass==__CLASS__){
            throw new
BadMethodCallException(__CLASS__ . '::' . __METHOD__ . ' may only br called from deriver classes.');
        }
        if(
$calledClass::isKey($key)){
            return
self::$_arrays[$calledClass][$key];
        } else {
            throw new
InvalidArgumentException("{$name} is no valid key of {$calledClass}");
        }
    }
   
   
/**
     * Returns an boolean indicating if there is a member of this enum type with this name.
     * @param $name
     * @return boolean
     * @access public
     * @static
     * @throws \BadMethodCallException
     */
   
public static function isMember($name){
       
$calledClass = get_called_class();
        if(
$calledClass==__CLASS__){
            throw new
BadMethodCallException(__CLASS__ . '::' . __METHOD__ . ' may only be called from deriver classes.');
        }
        return
array_key_exists($name,Enum::$_members[$calledClass]);
    }
   
   
/**
     * Returns an boolean indicating if there is a member of this enum type with this key.
     * @return boolean
     * @access public
     * @static
     * @throws \BadMethodCallException
     */
   
public static function isKey($key){
       
$calledClass = get_called_class();
        if(
$calledClass==__CLASS__){
            throw new
BadMethodCallException(__CLASS__ . '::' . __METHOD__ . ' may only br called from deriver classes.');
        }
        return
array_key_exists($key, self::$_arrays[$calledClass]);
    }
   
   
/**
     * Returns an boolean indicating if the given string is a valid PHP identifier
     *
     * @todo move this method to another class
     * @param $string
     * @return unknown_type
     * @access protected
     * @static
     */
   
private static function isValidIdentifier($string){
        return
preg_match("|^[a-zA-Z_][a-zA-Z0-9_]*$|i", $string);
    }
   
//------ INSTANCE ------//
    /**
     * The internal key of this instance
     * @var unknown_type
     * @access protected
     */
   
private $key;
   
   
/**
     * The name of this instance
     * @var unknown_type
     * @access protected
     */
   
private $name;
   
   
/**
     * constructs a new instance
     * @param $key the key o the instance
     * @param $name the name o the instance
     * @return unknown_type
     * @access protected
     */
   
protected function __construct($key, $name){
       
$this->key = $key;
       
$this->name = $name;
    }
   
   
/**
     * Returns the internal key of this instance.
     * @return unknown_type
     * @access public
     */
   
public function getKey(){
        return
$this->key;
    }
   
   
/**
     * returns the name of this instance.
     * @return string
     * @access public
     */
   
public function __toString(){
        return
$this->name;
    }
    
}
?>