<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
/*
* a mix of ArrayObject and ArrayIterator
* created to have ArrayIterator basics functionnalities on an ArrayObject
* and to iterate it on it real offset
*/
class ArrayObjectIterator extends ArrayObject
{
public function __construct ($array, $flags=0, $iterator_class = "ArrayIterator")
{
parent::__construct( $array, $flags, $iterator_class );
}
public function setCurrent($index,$strict=false) {
if (!array_key_exists($index,$this))return false;
$start=key($this);
if (($start == $index && $strict == false )|| $start === $index)return true;
if(is_int($index)) {
if ($index>$start) for ($i=0;$i<$index-$start;$i++) next($this);
else for ($i=0;$i<$start-$index;$i++) prev($this);
return true;
} else {
reset($this);
if ($strict) {
while (key($this)!==$index) {
if (next($this)===false)return false;
}
return true;
} else {
while (key($this)!=$index) {
if (next($this)===false)return false;
}
return true;
}
}
}
public function next(){
return next($this);
}
public function prev() {
return prev($this);
}
public function current() {
return current($this);
}
public function end() {
return end($this);
}
public function reset() {
return reset($this);
}
public function key() {
return key($this);
}
}
/**
* Class nException (modified EException) to manage Exception like errors and displays its like PHP standards messages
* @package namespaces
* @subpackage nException
* @author Salvan Gregory <dev@europeaweb.com>
* @version 1.a
* @copyright Copyright (c) 2008, Salvan Gregory europeaweb.com
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class nException extends Exception
{
public static $levels = array(E_ERROR,E_WARNING,E_NOTICE);
/*
* function to call if exists when method trigger() is called
*/
public static $trigger= array(E_ERROR =>'shownException',
E_WARNING=>'shownException',
E_NOTICE =>'shownException');
/*
* errors reporting: 0=> Silent mode
1=> Show error in the current page only
2=> Log error only
3=> Show error in the current page and log it.
*/
public static $reporting=array(E_ERROR=>1,E_WARNING=>1,E_NOTICE=>2);
/*
* String used as error title in logs and html
*/
public static $titles=array(E_ERROR=>'ERROR',E_WARNING=>'WARNING',E_NOTICE=>'NOTICE');
/*
* Show or not errors in the page, overide reporting
*/
public static $display = true;
/*
* if true, add trace to log message
*/
public static $log_verbose = false;
public function __construct($message, $code = 0) {
if (in_array($code,nException::$levels)) {
namespaces::$errors[$code][]=&$this;
} else namespaces::$errors[E_ERROR][]=&$this;
parent::__construct($message,$code);
}
/**
* method that show or/and log message and stop script execution as defined in the configuration
* or if an existing function is defined in the static var $trigger call this function
*/
public function trigger() {
$c=$this->getCode();
if (isset(nException::$trigger[$c]) && function_exists(nException::$trigger[$c])) {
return nException::$trigger[$c]($this);
}
//default:
if ($c!=E_NOTICE && $c!=E_WARNING) $c=E_ERROR;
$r=nException::$reporting;
//we show the error:
if (nException::$display==true && isset($r[$c]) && ($r[$c]==1 || $r[$c] == 3)) {
echo $this->dump();
}
//we log the error:
if (isset($r[$c]) && ($r[$c]==2 || $r[$c] == 3)) {
$this->log();
}
//stop execution if it's an error:
if ($c==E_ERROR) exit();
}
/**
* method to show the message
*/
private function dump() {
$c=$this->getCode();
if (isset(nException::$titles[$c])) $title=nException::$titles[$c];
else $title="nException";
$ret= "<font size='1'><table dir='ltr' border='1' cellspacing='0' cellpadding='1'>
<tr><th align='left' bgcolor='#f57900' colspan='5'>
<span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span>
".$title.": ".$this->getMessage()." in ".$this->file." on line <i>".$this->line."</i>
</th></tr>
<tr><th align='left' bgcolor='#e9b96e' colspan='5'>Call Stack</th></tr>
<tr><th align='center' bgcolor='#eeeeec'>#</th>
<th align='left' bgcolor='#eeeeec'>Line</th>
<th align='left' bgcolor='#eeeeec'>Function</th>
<th align='left' bgcolor='#eeeeec'>Args</th>
<th align='left' bgcolor='#eeeeec'>Location</th></tr>
";
$t=$this->getTrace();
$p=realpath('.');
$pp=realpath('..');
foreach ($t as $s=>$infos) {
$f=str_replace(array($p,$pp),array('.','..'),$infos['file']);
$args=array();
foreach ($infos['args'] as $v) {
$args[]=var_export($v,true);
}
$ret.="<tr>
<td bgcolor='#eeeeec' align='center'>".$s."</td>
<td bgcolor='#eeeeec' align='center'>".$infos['line']."</td>
<td bgcolor='#eeeeec' align='left'>".$infos['function']."</td>
<td bgcolor='#eeeeec'>".implode($args,'</br>')."</td>
<td title='".$infos['file']."' bgcolor='#eeeeec'>".$f."</td>
</tr>";
}
$ret.="</table></font>";
return $ret;
}
/**
* method that log the Exception
*/
private function log() {
$c=$this->getCode();
if (isset(nException::$titles[$c])) $title=nException::$titles[$c];
else $title="ERROR";
error_log("Namespaces [$title] : ".$this->getMessage()." in file ".$this->file." :".$this->line);
if (nException::$log_verbose==true){
$message=$this->getTraceAsString();
$message=explode("\n",$message);
foreach ($message as $s) {
error_log(" [VERBOSE] : ".$s);
}
}
}
public function __tostring() {
return $this->dump();
}
/**
* launch the Exception $exception and trigger it to fake an user defined error
*/
public static function nError($exception) {
try {
throw $exception;
} catch (Exception $e) {
$e->trigger();
}
}
}
/**
* Main class: include or require files in a name space.
* @package namespaces
* @author Salvan Gregory <dev@europeaweb.com>
* @version 1.0
* @copyright Copyright (c) 2008, Salvan Gregory europeaweb.com
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/
class namespaces extends ArrayObjectIterator
{
// arrays to store functions and classes names:
private static $func=array(),$class=array();
//the unique instance of the class:
private static $__;
//errors :
public static $errors=array(E_ERROR=>array(), E_WARNING=>array(), E_NOTICE=>array());
//whether or not to fix called functions and new objects in the namespace they are loaded:
public static $static=false;
//if false try to load functions or classes from others namespaces when they're not in the current:
public static $strict=false;
/**
* private constructor to allow only one instance
*/
private function namespaces ()
{
parent::__construct(array('GLOBAL'),ArrayObject::ARRAY_AS_PROPS);
}
/**
* public static constructor
*/
public static function create()
{
if (!isset(self::$__)) {
self::$__= new namespaces();
} else nException::nError(new nException('An instance of namespace is already defined !',E_NOTICE));
return self::$__;
}
/**
* disallow clone
*/
protected function __clone() {}
public static function use_namespace($index) {
if(!is_int($index)) {
$r=array_keys((array) self::$__ ,$index);
if (isset($r[0]))$index = $r[0];
else return false;
}
return self::$__->setCurrent($index);
}
public static function get_namespace() {
$r = current(self::$__);
if ($r==false) {
self::use_namespace('GLOBAL');
return 'GLOBAL';
} else return $r;
}
public static function set_namespace($namespace) {
if (is_string($namespace) && !in_array($namespace, (array) self::$__)) {
self::$__[]=$namespace;
}
use_namespace($namespace);
}
private static function load_file_into_namespace($file,$namespace=false,$static=-1) {
if ($namespace===false) $namespace=self::get_namespace();
else self::set_namespace($namespace);
if (!is_bool($static))$static= is_bool(self::$static) ? self::$static :false;
if (file_exists($file))$fp=file_get_contents($file);
else throw new nException('File "'.$file.'" doesn\'t exist !',E_WARNING);
preg_match_all('@(?<!public|static|private|protected)\s+function\s+(\w+)@',$fp,$res);
preg_match_all('@class\s+(\w+)@',$fp,$res1);
$rep =' '.$namespace.'_';
$f=isset($res[1]) ? array_unique( $res [1] ):array();
$c=isset($res1[1])? array_unique( $res1[1] ):array();
$res = implode('|',$f).'|'.implode('|',$c);
if ($static) {
//we add the namespace prefix before each functions and classes names:
$mask='@[\s\n\(\=](?='.$res.'[\s\(])@';
} else {
//we add the namespace prefix before functions and classes declarations only:
$mask='@(?<=function|class)\s+(?='.$res.'[\s\(])@';
}
//we clean the code :
$fp=preg_replace(array('@<\?php@',$mask),array('',$rep),$fp);
//we load classes and functions with their prefix :
if (@eval($fp)=== false){
throw new nException('Can\'t evaluate the code of file '.$file.' !',E_WARNING);
}
//for each class name we create a generic class and add the name to the static var $class:
foreach ($c as $cl) {
self::add_class($cl,$namespace);
}
// for each function name we create a generic function and add the name to the static var $func:
foreach ($f as $func) {
self::add_func($func,$namespace);
}
}
public static function require_to_namespace($file,$namespace=false,$static=-1)
{
self::load_file_into_namespace($file,$namespace,$static);
}
public static function include_to_namespace($file,$namespace=false,$static=-1)
{
try {
self::load_file_into_namespace($file,$namespace,$static);
} catch (Exception $e) {
$e->trigger();
}
}
public static function get_class_name($name)
{
$nm=self::get_namespace().'_'.$name;
if (isset(namespaces::$class[$nm])) return $nm;
elseif(namespaces::$strict==false) {
$cl=array_keys(self::$class,$name,true);
$ret=reset($cl);
while ($ret!=false && !class_exists($ret)) $ret=next($cl);
if ($ret!=false) return $ret;
}
nException::nError(new nException('Class '.$name.' not defined in namespace '.$nm.'!',E_NOTICE));
return false;
}
public static function get_func_name($name)
{
$nm=self::get_namespace().'_'.$name;
if (isset(self::$func[$nm])) return $nm;
elseif(self::$strict==false) {
$f=array_keys(self::$func,$name,true);
$f = current($f);
if ($f!=false) return $f;
}
nException::nError(new nException('Function '.$name.' not defined in namespace '.$nm.'!',E_NOTICE));
return false;
}
public static function add_class($classname, $namespace=false) {
if ($namespace==false) $namespace=self::get_namespace();
self::set_namespace($namespace);
if (!isset(self::$class[$namespace.'_'.$classname])){
if(!class_exists($classname)) eval(_create_abstractClass($classname));
else nException::nError(new nException('Class '.$classname.' is already defined !',E_NOTICE));
self::$class[$namespace.'_'.$classname]=$classname;
}
}
public static function add_func($funcname, $namespace=false) {
if ($namespace==false) $namespace=self::get_namespace();
self::set_namespace($namespace);
if (!isset(self::$func[$namespace.'_'.$funcname])){
if(!function_exists($funcname)) eval(_create_abstractFunction($funcname));
else nException::nError(new nException('Function '.$funcname.' is already defined !',E_NOTICE));
self::$func[$namespace.'_'.$funcname]=$funcname;
}
}
}//end of class namespaces
abstract class _abstractClass
{
public $_this;
function _abstractClass () {
$args = func_get_args();
$cl=get_class($this);
$name=namespaces::get_class_name($cl);
if ($name==false || $name==$cl || !class_exists($name)) {
nException::nError(new nException('Class '.$cl.' is not defined in a namespace !',E_WARNING));
}
$arg=implode('],$args[',array_keys($args));
if ($arg!='') $arg='$args['.$arg.']';
$this->_this= @eval('return new '.$name."(".$arg.");");
if ($this->_this===false) {
nException::nError(new nException('Class '.$cl.'('.$name.') error while creating the object !',E_ERROR));
}
}
public function __set($n,$v) {
$this->_this->$n=$v;
}
public function &__get($n) {
return $this->_this->$n;
}
public function __call($f,$a) {
renameObj($this);
return call_user_func_array(array($this->_this,$f),$a);
}
}
function _create_abstractClass ($cl) {
return '
class '.$cl.' extends _abstractClass {
public static function create() {
$args = func_get_args();
$name=namespaces::get_class_name("'.$cl.'");
$arg=implode(\'],$args[\',array_keys($args));
if ($arg!="")$arg=\'$args[\'.$arg.\']\';
return @eval("return new ".$name."(".$arg.");");
}
};';
}
function _create_abstractFunction ($func) {
return '
function '.$func.'() {
$args = func_get_args();
$nm=namespaces::get_func_name("'.$func.'");
if (function_exists($nm))return call_user_func_array($nm,$args);
else {
nException::nError(new nException("Function '.$func.' not defined in a namespace !",E_WARNING));
}
}';
}
function use_namespace($namespace) {
return namespaces::use_namespace($namespace);
}
function get_namespace() {
return namespaces::get_namespace();
}
function set_namespace($namespace) {
return namespaces::set_namespace($namespace);
}
function require_to_namespace($file,$namespace=false,$static=-1) {
namespaces::require_to_namespace($file,$namespace,$static);
}
function include_to_namespace($file,$namespace=false,$static=-1) {
namespaces::include_to_namespace($file,$namespace,$static);
}
function renameObj($obj=false) {
if ($obj!==false && is_object($obj)) {
$k=array_keys($GLOBALS, $obj, true);
foreach ($k as $key) {
if (isset($obj->_this))$GLOBALS[$key]=&$obj->_this;
}
} else {
foreach ($GLOBALS as $k=>$v) {
if (is_object($v) && isset($v->_this))$GLOBALS[$k]=&$v->_this;
}
}
}
/**
* init namespaces
* default namespace is GLOBAL (current($__) return 'GLOBAL')
*/
$_ENV['__NAMESPACES__']= $__ = namespaces::create();
?>
|