Login   Register  
PHP Classes
elePHPant
Icontem

File: class/Co3/CodeGen/Enum.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  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: 3 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($keyself::$_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;
    }
     
}
?>