PHP Type Safe Enum

This snippet provides a simple implementation of type safe enums for PHP 5.3.

Snippet

Abstraction

The Enum base class.

// (c) Copyright 2011 Bedican Solutions (www.bedican.co.uk)

abstract class Enum
{
	private static $registered = false;
	private static $values = array();

	private final function __construct($args)
	{
		$this->init($args);
	}
	
	protected abstract function init($args);
	protected abstract static function addValues();
	
	private static function register()
	{
		if(!self::$registered) {
			self::$registered = true;
			static::addValues();
		}
	}
	
	protected static function addValue($name, $args = array())
	{
		$className = get_called_class();
		self::$values[$name] = new $className($args);
	}
	
	public static function getValues()
	{
		self::register();
		return array_values(self::$values);
	}
	
	public static function __callStatic($name, $args)
	{
		self::register();
		if(!array_key_exists($name, self::$values)) {
			throw new EnumNotFoundException('Unknown enum value '.get_called_class().'::'.$name);
		}
		
		return self::$values[$name];
	}
}

class EnumNotFoundException extends Exception
{
}

Implementing Class

A class representing a http status.

// (c) Copyright 2011 Bedican Solutions (www.bedican.co.uk)

class HttpStatus extends Enum
{
	private $code;
	private $message;
	
	protected function init($args)
	{
		list($this->code, $this->message) = $args;
	}
	
	public function getCode()
	{
		return $this->code;
	}
	
	public function getMessage()
	{
		return $this->message;
	}
	
	public function toString()
	{
		return $this->getCode().' '.$this->getMessage();
	}
	
	public function __toString()
	{
		return $this->toString();
	}
	
	public static function getHttpStatus($code)
	{
		$values = self::getValues();
		foreach($values as $value) {
			if($value->getCode() == $code) {
				return $value;
			}
		}
		
		return null;
	}
	
	protected static function addValues()
	{
		// 2xx OK
		self::addValue('OK', array(200, 'OK'));
		self::addValue('CREATED', array(201, 'Created'));
		self::addValue('ACCEPTED', array(202, 'Accepted'));
		self::addValue('NON_AUTHORATIVE', array(203, 'Non-Authoritative Information'));
		self::addValue('NO_CONTENT', array(204, 'No Content'));
		self::addValue('RESET_CONTENT', array(205, 'Reset Content'));
		self::addValue('PARTIAL_CONTENT', array(206, 'Partial Content'));

		// 3xx Redirection
		self::addValue('MUTIPLE_CHOICES', array(300, 'Multiple Choices'));
		self::addValue('MOVED_PERMANENTLY', array(301, 'Moved Permanently'));
		self::addValue('FOUND', array(302, 'Found'));
		self::addValue('SEE_OTHER', array(303, 'See Other'));
		self::addValue('NOT_MODIFIED', array(304, 'Not Modified'));
		self::addValue('USE_PROXY', array(305, 'Use Proxy'));
		self::addValue('TEMPORARY_REDIRECT', array(307, 'Temporary Redirect'));
		
		// 4xx Client Error
		self::addValue('BAD_REQUEST', array(400, 'Bad Request'));
		self::addValue('UNAUTHORIZED', array(401, 'Unauthorized'));
		self::addValue('PAYMENT_REQUIRED', array(402, 'Payment Required'));
		self::addValue('FORBIDDEN', array(403, 'Forbidden'));
		self::addValue('NOT_FOUND', array(404, 'Not Found'));
		self::addValue('METHOD_NOT_ALLOWED', array(405, 'Method Not Allowed'));
		self::addValue('NOT_ACCEPTABLE', array(406, 'Not Acceptable'));
		self::addValue('PROXY_AUTHENTICATION_REQUIRED', array(407, 'Proxy Authentication Required'));
		self::addValue('REQUEST_TIMEOUT', array(408, 'Request Timeout'));
		self::addValue('CONFLICT', array(409, 'Conflict'));
		self::addValue('GONE', array(410, 'Gone'));
		self::addValue('LENGTH_REQUIRED', array(411, 'Length Required'));
		self::addValue('PRECONDITION_FAILED', array(412, 'Precondition Failed'));
		self::addValue('ENTITY_TOO_LARGE', array(413, 'Request Entity Too Large'));
		self::addValue('URI_TOO_LONG', array(414, 'Request-URI Too Long'));
		self::addValue('UNSUPPORTED_MEDIA_TYPE', array(415, 'Unsupported Media Type'));
		self::addValue('RANGE_NOT_SATISFIABLE', array(416, 'Requested Range Not Satisfiable'));
		self::addValue('EXPECTATION_FAILED', array(417, 'Expectation Failed'));
		
		// 5xx Server Error
		self::addValue('INTERNAL_SERVER_ERROR', array(500, 'Internal Server Error'));
		self::addValue('NOT_IMPLEMENTED', array(501, 'Not Implemented'));
		self::addValue('BAD_GATEWAY', array(502, 'Bad Gateway'));
		self::addValue('SERVICE_UNAVAILBLE', array(503, 'Service Unavailable'));
		self::addValue('GATEWAY_TIMEOUT', array(504, 'Gateway Timeout'));
		self::addValue('VERSION_NOT_SUPPORTED', array(505, 'HTTP Version Not Supported'));
	}
}

Example Usage

Both $okStatus and $notFoundStatus are instances of HttpStatus.

$okStatus = HttpStatus::OK();
$notFoundStatus = HttpStatus::NOT_FOUND();

print($okStatus->getCode()); // 200
print($notFoundStatus->getCode()); // 404