Login   Register  
PHP Classes
elePHPant
Icontem

File: TypeHintHandler.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Martin Alterisio  >  Type Hint Class  >  TypeHintHandler.php  >  Download  
File: TypeHintHandler.php
Role: Class source
Content type: text/plain
Description: TypeHints handler.
Class: Type Hint Class
Implement type hinting support for base PHP types
Author: By
Last change: Accessible without user login
Date: 7 years ago
Size: 4,793 bytes
 

Contents

Class file image Download
<?php
/**
 * @package typehintclass
 */

/**
 * Class that handles type hinting errors and checks type hint
 * classes. Singleton.
 */
final class TypeHintHandler {
    
/**
     * Error handler that was replaced by the one from this object
     * @var function|null
     */
    
private $oldErrorHandler;
    
/**
     * Cached info parsed from error message.
     * @var array
     */
    
private $parsedErrors;
    
/**
     * Cached results of checking which classes are type hints.
     * @var array
     */
    
private $typeHintClasses;
    
    
/**
     * Constructor. Activates the error handling.
     */
    
private function __construct() {
        
$this->oldErrorHandler set_error_handler(array($this'errorHandler'));
        
$this->parsedErrors = array();
        
$this->typeHintClasses = array();
    }
    
    
/**
     * Single instance of TypeHintHandler.
     * @var TypeHintHandler
     */
    
private static $instance;
    
    
/**
     * Sets up the single instance of this handler.
     */
    
public static function setUp() {
        if (
self::$instance === null) {
            
self::$instance = new TypeHintHandler();
        }
    }
    
    
/**
     * Returns the single instance of this handler.
     * @return TypeHintHandler The singleton instance.
     */
    
public static function getInstance() {
        
self::setUp();
        return 
self::$instance;
    }
    
    
/**
     * Parses an error string to find out if it is a type hint failure
     * and to gather the info about this error in particular.
     * @param string $errstr Error message.
     * @return array|null Info on the parsed error.
     */
    
private function parseErrorString($errstr) {
        if (isset(
$this->parsedErrors[$errstr])) {
            return 
$this->parsedErrors[$errstr];
        }
        
$parsedError null;
        if (
preg_match('/^Argument ([0-9]+) passed to ([a-zA-Z0-9_:]+)\(\) must be an instance of ([a-zA-Z0-9_:]+),/'$errstr$match)) {
            
$parsedError = array(
                
'argnum'   => $match[1],
                
'class'    => null,
                
'function' => $match[2],
                
'typehint' => $match[3],
            ); 
            if (
preg_match('/^([a-zA-Z0-9_]+)::([a-zA-Z0-9_]+)$/'$match[2], $match)) {
                
$parsedError['class'] = $match[1];
                
$parsedError['function'] = $match[2];
            }
        }
        
$this->parsedErrors[$errstr] = $parsedError;
        return 
$parsedError;
    }
    
    
/**
     * Error handling routine.
     * @private
     * @param int $errno Error code.
     * @param string $errstr Error message.
     * @param string $errfile File where the error occurred.
     * @param int $errline The line number where the error occurred.
     * @param array $errcontext The context where the error occurred.
     */
    
public function errorHandler($errno$errstr$errfile$errline$errcontext) {
        if (
$errno == E_RECOVERABLE_ERROR) {
            if (
$parsedError $this->parseErrorString($errstr)) {
                
$backtrace debug_backtrace();
                
$value = @$backtrace[1]['args'][$parsedError['argnum']-1];
                if (
$this->solveTypeHintFailure($parsedError['typehint'], $value)) {
                    return;
                }
            }
        }
        if (
$this->oldErrorHandler) {
            return 
call_user_func($this->oldErrorHandler$errno$errstr$errfile$errline$errcontext);
        } else {
            return 
false;
        }
    }
    
    
/**
     * Solves a type hint failure, deciding to continue or not.
     * @param string $typeHint The type hint used.
     * @param mixed $value The value that failed the type hint.
     * @return bool Whether to continue or not.
     */
    
private function solveTypeHintFailure($typeHint$value) {
        if (
$this->isTypeHintClass($typeHint)) {
            return 
call_user_func(array($typeHint'isTypeHintFor'), $value);
        }
        return 
false;
    }
    
    
/**
     * Indicates if a class is a type hint class.
     * 
     * @param string $className The class.
     * @return bool True if the class is a type hint class.
     */
    
public function isTypeHintClass($className) {
        if (isset(
$this->typeHintClasses[$className])) {
            return 
$this->typeHintClasses[$className];
        }
        
$this->typeHintClasses[$className] = false;
        if (
class_exists($className)) {
            if (
in_array('TypeHint'class_implements($className))) {
                
$this->typeHintClasses[$className] = true;
            }
        }
        return 
$this->typeHintClasses[$className];
    }
}
?>