PHP Classes

File: TypeHintHandler.php

Recommend this page to a friend!
  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: 16 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];
    }
}
?>