<?php 
/** 
* @package simpleMVC 
* @class smvcShutdownManager 
* @since 2010-12-20 
* @licence dual licence LGPL / MIT 
* @author jonathan gotti <jgotti at jgotti dot net> 
*/ 
class smvcShutdownManager{ 
 
    static private $_registeredCallbacks = array(); 
    static private $_byPassCallBacks = false; 
    static private $_registered = false; 
    static private $_id = 0; 
 
    /** 
    * Check that given callable is registered by shutdown manager. It also allow to check that smvcShutdownManager is registered itself 
    * @param callback $callBack       check that the given callback (or id of registered callback return by register method) is registered (if null then check that smvcShutdownManager itself is registered) 
    * @param bool     $returnPriority if true the actual priority level of the callback will be return instead of bool (be aware it may return 0 in such case that doesn't mean false) 
    * @return bool or integer if $returnPriority is passed to true 
    */ 
    static public function isRegistered($callBack=null,$returnPriority=false){ 
        if( null === $callBack ){ 
            return self::$_registered; 
        } 
 
        if( is_int($callBack) ){ 
            return isset(self::$_registeredCallbacks[$callBack])?($returnPriority?self::$_registeredCallbacks[$callBack][1]:true):false; 
        } 
 
        foreach(self::$_registeredCallbacks as $cb){ 
            if( $cb[0]===$callBack) 
                return $returnPriority?$cb[1]:true; 
        } 
        return false; 
    } 
 
    /** 
    * register a callback function to be executed as a shutdown fucntion 
    * @param callback $callBack the callback to register, if already registered then it 
    * @param int      $priority the priority level of the callback (higher level means later call) 
    * @param mixed    $param    you can add as many optionnal parameter as  you want to the callback 
    * @return int     internal callback id 
    */ 
    static public function register($callBack,$priority=0){ 
        if(! self::$_registered ){ 
            register_shutdown_function(array(__class__,'_registered_shutdown')); 
            self::$_registered = true; 
        } 
        $params = func_get_args(); 
        self::$_registeredCallbacks[++self::$_id] = array($callBack,(int) $priority,self::$_id,array_slice($params,2)); 
        return self::$_id; 
    } 
 
    /** 
    * unregister previously registered callback 
    * @param callback $callBack the callback to unregister (or the callback id returned by register method ) 
    *                           /!\ if null is given then will unregister all previously registered callback. 
    * @return bool return true if successfully removed else return false 
    */ 
    static public function unregister($callBack){ 
        if( is_null($callBack) ){ 
            self::$_registeredCallbacks  = array(); 
            return true; 
        } 
        if( is_int($callBack) ){ 
            if( !isset(self::$_registered[$callBack])) 
                return false; 
            unset(self::$_registered[$callBack]); 
            return true; 
        } 
        foreach(self::$_registeredCallbacks as $k=>$cb){ 
            if( $cb[0]===$callBack){ 
                unset(self::$_registeredCallbacks[$k]); 
                return true; 
            } 
        } 
        return false; 
    } 
 
    /** 
    * shutdown the script by calling exit. 
    * @param mixed $status may be a string as in die or a status code (@see exit) 
    * @param bool  $byPassCallBacks if true then will do a normal exit without calling any of the registered callbacks 
    */ 
    static public function shutdown($status=0,$byPassCallBacks=false){ 
        self::$_byPassCallBacks = $byPassCallBacks; 
        exit($status?$status:0); 
    } 
 
    /** 
    * THIS IS NOT INTENTED TO BE CALLED OTHER THAN INTERNALLY 
    * the only reason for this to be public is that it's a necessity for register_shutdown_function to see it 
    * there's no reason at all for you to call this 
    * @internal 
    */ 
    static public function _registered_shutdown(){ 
        if( self::$_byPassCallBacks ) 
            return; 
        #- first sort the stack 
        uasort(self::$_registeredCallbacks,array(__class__,'_compare')); 
        foreach( self::$_registeredCallbacks as $cb){ 
            call_user_func_array($cb[0],$cb[3]); 
        } 
    } 
 
    /** 
    * used to sort callbacks by priority respecting their registering order 
    * @internal 
    * @private 
    */ 
    static private function _compare($a,$b){ 
        if( $a[1] === $b[1] ){ 
            return $a[2] > $b[2]?1:-1; 
        } 
        return $a[1] > $b[1]?1:-1; 
    } 
} 
 
 |