Advertisement
Guest User

overloader.php

a guest
Sep 30th, 2017
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.63 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * Trait helps to allow for some limited overloading of
  5.  * methods in the class this is attached to.
  6.  */
  7. trait Overloader {
  8.  
  9.     /**
  10.      * Where the magic happens
  11.      * @param  string $name The name of the function that was called
  12.      * @param  array $args An array containing arguments
  13.      */
  14.     public function __call($method, $parameters)
  15.     {
  16.         // We'll need some information about our class and methods
  17.         // before we can route this call (if it is routable)
  18.         $reflection = new \ReflectionClass(get_class($this));
  19.        
  20.         // Grab the possible matches
  21.         $matches = $this->__filterMethodsForMatches($method, $reflection->getMethods());
  22.  
  23.         // If matches are found, let's evaulate them to see if they can be called.
  24.         if( count($matches) > 0 ) :
  25.             // We'll take a look at the parameters and then get the datatypes
  26.             // for each one.
  27.             $parameterTypes = $this->__resolveparameterTypes($parameters);
  28.  
  29.             /**
  30.              * In order for there to be a match a few conditions must be met.
  31.              * 1) The first part of the function name must match exactly
  32.              * 2) The number of paramters passed must be in the same order
  33.              * as the definition and match the type.
  34.              */
  35.             foreach($matches as $candidate ) :
  36.                 // Get information about the candidate
  37.                 $info =  $this->__candidateMatch($reflection->getMethod($candidate), $parameterTypes);              
  38.                 if( $info['provided_parameters'] == $info['matched_parameter_types'] && $info['primary_parameter_matches']) :
  39.                     return call_user_func_array([$this, $candidate], $parameters);
  40.                 endif;
  41.             endforeach;
  42.         endif;
  43.  
  44.         /**
  45.          * First, if this method is being called by
  46.          * the parent, let's make sure we get it out of the way
  47.          * first.
  48.          */
  49.         if( is_callable(['parent', '__call']) ) :
  50.             parent::__call($method, $parameters);
  51.         endif;
  52.     }
  53.  
  54.     /**
  55.      * Filter through all the methods in the class and look for any that will be possible matches.
  56.      * @param  string $methodName   The name of the method that was called
  57.      * @param  array $classMethods The PHP Reflection list of methods
  58.      * @return array               Possible Matches
  59.      */
  60.     private function __filterMethodsForMatches($methodName, $classMethods)
  61.     {
  62.         // We'll return this at the end if we find any matches
  63.         $possibleMatches = [];
  64.  
  65.         // Cycle through each method found and see if it
  66.         // matches the pattern we are looking for
  67.         foreach($classMethods as $classMethod ) :          
  68.             if(strstr($classMethod->name, $methodName)) {
  69.                 array_push($possibleMatches, $classMethod->name);
  70.             }
  71.         endforeach;
  72.  
  73.         return $possibleMatches;
  74.     }
  75.  
  76.     /**
  77.      * Creates an array matching the order of the parameters provided
  78.      * but instead of the datatype of the parameter.
  79.      *      
  80.      * @param  array  $parameters [description]
  81.      * @return array            
  82.      */
  83.     private function __resolveparameterTypes($parameters = [])
  84.     {
  85.         if( empty($parameters) ) return [];
  86.  
  87.         $resolved = [];
  88.  
  89.         foreach( $parameters as $parameter ) :
  90.             switch(gettype($parameter)) {
  91.                 case 'double':
  92.                     $resolved[] = 'float'; // gettype() returns 'double' instead of float
  93.                     break;
  94.                 case 'object':
  95.                     $reflector = new \ReflectionClass($parameter);
  96.                     $resolved[] = $reflector->getName();
  97.                     break;
  98.                 // boolean is an alias for bool
  99.                 // gettype returns the alias which make fail the signature check
  100.                 case 'boolean':
  101.                     $resolved[] = 'bool';
  102.                     break;
  103.                 default:
  104.                     $resolved[] = gettype($parameter);
  105.             }
  106.         endforeach;
  107.  
  108.         return $resolved;
  109.     }
  110.  
  111.     /**
  112.      * Checks to see if a given candidate matches based on the information provided
  113.      * @param  ReflectionMethod $candidate      The candidate method
  114.      * @param  array  $paramaterTypes [description]
  115.      * @return [array]                 [description]
  116.      */
  117.     private function __candidateMatch($candidate, $parameterTypes = [])
  118.     {
  119.         $has_params = count($candidate->getParameters());
  120.  
  121.         $info = [
  122.             'defined_parameters'        => $has_params,
  123.             'provided_parameters'       => count($parameterTypes),
  124.             'matched_parameter_types'   => 0,
  125.             'primary_parameter_matches' => false,
  126.         ];
  127.  
  128.         if(0 < $has_params)
  129.         {
  130.             // We'll spin through the candidates paramter requirements and see if they match the appropriate types
  131.             foreach ($candidate->getParameters() as $index => $parameter)
  132.             {
  133.                 // Some methods may have default values attached at the end
  134.                 if( ! array_key_exists($index, $parameterTypes))
  135.                     break;
  136.  
  137.                 if( ! is_null($parameter->getType()) && $parameter->getType() == $parameterTypes[$index])
  138.                 {
  139.                     $info['matched_parameter_types']++;
  140.  
  141.                     if( $index == 0 )
  142.                         $info['primary_parameter_matches'] = true;
  143.                 }
  144.             }
  145.         }
  146.  
  147.         else
  148.             $info['primary_parameter_matches'] = true;
  149.  
  150.         return $info;
  151.     }
  152. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement