Login   Register  
PHP Classes
elePHPant
Icontem

File: Xyndravandria/Erozaver/Erozaver.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Mauro Di Girolamo  >  Xyndravandria Erozaver  >  Xyndravandria/Erozaver/Erozaver.php  >  Download  
File: Xyndravandria/Erozaver/Erozaver.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Xyndravandria Erozaver
Validate function parameters with type hinting
Author: By
Last change: Alpha 0.0.0
Date: 2013-05-22 13:23
Size: 13,169 bytes
 

Contents

Class file image Download
<?php
/*
=============================================================================================================================================
|   This file is part of a project released under the terms of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt).                 |
|                                                                                                                                           |
|   You should be given a copy of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt) within the same directory as the README.md;   |
|   if not, you can get a copy at http://Xyndravandria.ohost.de/XyndravandriaPHPLicense.txt .                                               |
|                                                                                                                                           |
|   The copyright (c) of this project is owned by Mauro Di Girolamo <maurodigirolamo@.web.de>.                                              |
============================================================================================================================================|



Xyndravandria Erozaver
----------------------
Alpha 0.0.0

Xyndravandria is the name of a collection of projects designed and developed by Mauro Di Girolamo (maurodigirolamo@web.de); he is therefore the copyright (c) owner of Xyndravandria itself and all of its projects.

Xyndravandria Erozaver is released under the terms of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt). You should be given a copy of the Xyndravandria PHP License (XyndravandriaPHPLicense.txt) within the same directory as the README.md; if not, you can get a copy at http://Xyndravandria.ohost.de/XyndravandriaPHPLicense.txt . There might be a release under a freer license for a later, more stable version.

The documentation is either included in ./admin_media/Documentation/ or can be read at http://Xyndravandria.ohost.de/Erozaver/Documentation/.

All projects:

   Xyndravandria Averazain
   http://github.com/MauroDiGirolamo/Xyndravandria_Averazain
   PHP
   Averazain is an Ajax framework supporting also JavaScript disabled clients perfectly - including search engines like Google.
   
   Xyndravandria Dyverath
   http://github.com/MauroDiGirolamo/Xyndravandria_Dyverath
   PHP
   Dyverath is a database access wrapper.
   
   Xyndravandria Erozaver
   http://github.com/MauroDiGirolamo/Xyndravandria_Erozaver
   PHP
   Erozaver is a class extending the type hinting given by the PHP engine (additional support for basic type hinting and size constraints).
   
   Xyndravandria Mondraviel
   http://github.com/MauroDiGirolamo/Xyndravandria_Mondraviel
   PHP
   Mondraviel is a class used to separate HTML from PHP code by firstly register models - files containing place holders embedded in HTML code - and then later fill them dynamically with content by passing values for the place holders.
*/

namespace Xyndravandria\Erozaver;

// TODO: Thing about enabling settype( ) again.
/// Erozaver extends the type hinting (see
/// http://de3.php.net/manual/language.oop5.typehinting.php
/// to know what type hinting is) given by PHP engine:
/// <ul><li>Makes basic type hinting possible</li>
/// <li>Allows size constraints</li></ul>
/// The syntax of size constraints is: @verbatim
/// Type\Operator_Length $Variable @endverbatim
/// Operator can either be SizeEqual, SizeMaximum,
/// SizeMinimum or SizeInterval. @n
/// When using SizeInterval, the syntax will be
/// @verbatim Type\SizeInterval_Minimum_Maximum @endverbatim
/// Example: @verbatim function Test( integer\SizeInterval_5_10 $Value ) { } @endverbatim
/// $Value will have to be an integer and its size has
/// to be between 4 and 11. @n @n
/// Whenever there is an invalid argument in type and
/// or length passed to a function or method, an
/// XyndravandriaErozaverException is thrown. @n @n
/// If you want to use size constraints within type
/// hintings for your own classes, they have to
/// implement the HasLength interface and, as a
/// consequence, offer a Length( ) method.
/// @note 
/// @verbatim \set_error_handler( 'Xyndravandria\Erozaver\Erozaver::HandleError' ); @endverbatim
/// will be called when this class is loaded. @n
/// To use your own error handler, see @ref
/// Xyndravandria::Erozaver::Erozaver::RegisterHandler( )
/// "Erozaver::RegisterHandler( )".
/// @abstract
abstract class Erozaver {
   
   /// An exception handler which has been registered by
   /// a user of the framework. @n
   /// It is called when an Exception thrown does not
   /// come from the framework.
   /// <dl class = "type"><dt><b>%Type:</b></dt>
   /// <dd>callback</dd></dl>
   /// @private 
   /// @static
   private static $UserExceptionHandler = null;
   
   /// Calls the exception handler registered in
   /// Erozaver::$UserExceptionHandler.
   /// @public
   /// @static
   /// @param array $Argument: The arguments to be passed to
   /// the exception handler.
   /// @returns mixed
   /// @note $Argument is an optional parameter.
   public static function UserExceptionHandler( array $Argument = array( ) ) {
      return \is_null( self::$UserExceptionHandler ) ? false : \call_user_func_array( self::$UserExceptionHandler, $Argument );
   }
   
   /// An error handler which has been registered by a
   /// user of the framework. @n
   /// It is called when an error occurs which does not
   /// come from the framework.
   /// <dl class = "type"><dt><b>%Type:</b></dt>
   /// <dd>callback</dd></dl>
   /// @private 
   /// @static
   private static $UserErrorHandler = null;
   
   /// Calls the error handler registered in
   /// Erozaver::$UserErrorHandler.
   /// @public
   /// @static
   /// @param array $Argument: The arguments to be passed
   /// to the error handler.
   /// @returns mixed
   /// @note $Argument is an optional parameter.
   public static function UserErrorHandler( array $Argument ) {
      return \is_null( self::$UserErrorHandler ) ? false : \call_user_func_array( self::$UserErrorHandler, $Argument );
   }
   
   /// Used as an argument for Erozaver::RegisterHandler( )
   /// to register an exception handler.
   const Type_ExceptionHandler = 1;
   
   /// Used as an argument for Erozaver::RegisterHandler( )
   /// to register an error handler.
   const Type_ErrorHandler = 2;
   
   /// Registers a user handler to Erozaver.
   /// @public 
   /// @static
   /// @param callback $Handler: The handler to be
   /// registered.
   /// @param integer $Type: The type of the handler to
   /// be registered. @n
   /// Currently, it can either be
   /// Erozaver::Type_ExceptionHandler or
   /// Erozaver::Type_ErrorHandler.
   public static function RegisterHandler( $Handler, $Type ) {
      try {
         $ReflectionFunction = new ReflectionFunction( $Handler );
      } catch( \Exception $Exception ) {
         throw new XyndravandriaErozaverException( $Exception->getMessage( ) );
      }
      if( \count( $ReflectionFunction::getParameters( ) ) != 1 )
         throw new XyndravandriaErozaverException( 'The given handler wants more than one parameter.' );
      elseif( $Type == self::Type_ExceptionHandler )
         self::$UserExceptionHandler = $Handler;
      elseif( $Type == self::Type_ErrorHandler )
         self::$UserErrorHandler = $Handler;
      else
         throw new XyndravandriaErozaverException( '$Type is not either Erozaver::Type_ExceptionHandler or Erozaver::Type_ErrorHandler.' );
      return;
   }
   
   /// Method which is registered as an error handler.
   /// @public
   /// @static
   /// @param $Level: The error level of the error
   /// occured.
   /// @param $Message: The message of the error occured.
   /// @note Calls Erozaver::$UserErrorHandler if the
   /// error does not concern extended type hinting.
   public static function HandleError( $Level, $Message ) {
      // TODO: Replace regex with a more high-performance algorithmn based on string functions / char by char looping.
      if( $Level == E_RECOVERABLE_ERROR ) { // TODO: Syntax \ and namespaces within object type hints.
         if( ! \preg_match( '#^Argument (\d+) passed to (.+) must be an instance of (.+)((\w+)_(\w+))?, (instance of)?(\w+) given#U', $Message, $Match ) ) // TODO: Optimise regex.
            return false;
         else {
            list( $PartUseless, $File, $Line ) = \preg_match( '#called in (.+) on line (\d+) and defined#U', $Message, $FileInformation ) ? $FileInformation : array( '', 'Unknown', 'Unknown' );
            list( $Message, $ArgumentNumber, $FunctionOrMethod, $Hint, $SizeConstraint, $Operator, $HintedSize, $Useless, $Given ) = $Match;
            if( ! empty( $SizeConstraint ) ) {
               $Hint[ \strlen( $Hint ) - 1 ] == '\\' && $Hint = \substr( $Hint, 0, \strlen( $Hint ) - 1 );
               if( \in_array( $Hint, array( 'boolean', 'resource', 'NULL', 'unknown type' ) ) ) {
                  throw new XyndravandriaErozaverException( 'Size constraints are only possible for integers, doubles, strings, arrays and objects.' );
                  return true;
               } else {
                  $Backtrace = \debug_backtrace( );
                  $Argument = $Backtrace[ 1 ][ 'args' ][ $ArgumentNumber - 1 ];
                  $ArgumentString = '';
                  if( $Hint == 'array' )
                     $ArgumentSize = \count( $Argument );
                  elseif( \class_exists( $Hint ) ) {
                     if( ! ( $Argument instanceof HasLength ) ) {
                        throw new XyndravandriaErozaverException( 'If you want to use size constraints within type hintings for your own classes, they have to implement the HasLength interface and, as a consequence, offer a Length( ) method.' );
                        return true;
                     } else
                        $ArgumentSize = $Argument->Length( );
                  } else {
                     $ArgumentString = \strval( $Argument );
                     \gettype( $Argument ) == 'double' && $ArgumentString = \str_replace( '.', '', $ArgumentString );
                     $ArgumentSize = \strlen( $ArgumentString );
                  }
                  switch( $Operator ) { // TODO: Validate that $HintedSize is an integer.
                     case 'SizeEquals' :
                        $SizeInvalid = $ArgumentSize != $HintedSize;
                        $OperatorError = 'hinted size and argument size are not equal';
                        break;
                     case 'SizeMaximum' :
                        $SizeInvalid = $ArgumentSize > $HintedSize;
                        $OperatorError = 'argument size is bigger than hinted size, but should be smaller or equal';
                        break;
                     case 'SizeMinimum' :
                        $SizeInvalid = $ArgumentSize < $HintedSize;
                        $OperatorError = 'argument size is smaller than hinted size, but should be bigger or equal';
                        break;
                     case 'SizeInterval' :
                        $Explode = explode( '_', $HintedSize );
                        if( \count( $Explode ) != 2 ) {
                           throw new XyndravandriaErozaverException( 'Syntax error in type hint; missing _. File: ' . $File . '. Line: ' . $Line . '. Function or method called: ' . $FunctionOrMethod . '. Argument number: ' . $ArgumentNumber . '. Argument value: ' . ( \class_exists( $Hint ) ? '*object*' : $Argument ) . '.' );
                           return true;
                        } else {
                           list( $Minimum, $Maximum ) = $Explode;
                           $SizeInvalid = ! ( $ArgumentSize >= $Minimum && $ArgumentSize <= $Maximum );
                           $OperatorError = 'argument size is ' . $ArgumentSize . ', but has to be between ( ' . $Minimum . ' - 1 ) and ( ' . $Maximum . ' + 1 )';
                           break;
                        }
                     default :
                        throw new XyndravandriaErozaverException( 'Unknown operator \'' . $Operator . '\' within type hint. File: ' . $File . '. Line: ' . $Line . '. Function or method called: ' . $FunctionOrMethod . '. Argument number: ' . $ArgumentNumber . '. Argument value: ' . ( \class_exists( $Hint ) ? '*object*' : $Argument ) . '.' );
                        return true;
                  }
               }
               if( $SizeInvalid ) {
                  throw new XyndravandriaErozaverException( 'Invalid size of argument detected - ' . $OperatorError . '. File: ' . $File . '. Line ' . $Line . '. Function or method called: ' . $FunctionOrMethod . '. Argument number: ' . $ArgumentNumber . '. Argument value: ' . ( \class_exists( $Hint ) ? '*object*' : $Argument ) . '. Operator: ' . $Operator . '. Hinted size: ' . $HintedSize . '. Argument size: ' . $ArgumentSize . '.' );
                  return true;
               }
            }
            return $Hint == $Given ? true : Erozaver::UserErrorHandler( array( $Level, $Message ) );
         }
      } else
         return false;
   }
   
}
\set_error_handler( 'Xyndravandria\Erozaver\Erozaver::HandleError' );
?>