I have been working on a class to use Reflection to interrogate other PHP classes and interfaces, what I want to know from anyone with more experience of this is, is there anything else I can add, or is there a better way of doing the things I am trying to do.In essence I want to be able to use the interrogator to tell me everything it can about a class I give it, interfaces, parents, methods etc etc. When working on large multi-file projects this would give you an idea of the structure of the code and where to find things you need or want to change, eg you change a method in a parent only to find it was overridden by a child class, this should tell you if methods etc are overridden.thoughts / comments etc welcome.<?php/* Test / Dummy classes and interfaces for testing */interface i1{  const interface_i1_version = '1.0.0';  public function fred();}interface i2 extends i1{  const interface_i2_version = '2.0.0';}interface i3{  const interface_i3_version = '3.0.0';}class c1{  const class_c1_version = '1.0.0';  private $test1;  var $test2;  var $test3 = 'fred';  public function __construct()    {    }  public function foo()    {    }}class c2 extends c1 implements i3{  const class_c2_version = '2.0.0';  public function bar()    {    }}class c3 extends c2 implements i1,i2{  const class_c3_version = '3.0.0';  public static $Test = sub;  public function foo($bob = 1)    {    }  public function fred()    {    }}class c4 extends c3{  const class_c4_version = '3.0.0';  public static $Test = bob;  public function foo($bob = 1)    {    }}/* The real class to do the work */class interogate{  private $constants = Array();  private function get_type($ro)    {      return implode(' ', Reflection::getModifierNames($ro->getModifiers()));    }  private function in_array_r($needle, $haystack, $strict = true)    {      foreach ($haystack as $item)        {          if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && $this->in_array_r($needle, $item, $strict)))            {              return true;            }        }      return false;    }  private function check_parent($name, $parent)    {      foreach ($parent as $p)        {          if ($name == $p['name'])            {              return $p;            }        }      return false;    }  private function update_global_constants($name, $location)    {      foreach ($this->constants as $constant)        {          if ($constant['name'] === $name)            {              return;            }        }      $constant = Array('name' => $name, 'location' => $location);      $this->constants[] = $constant;    }  private function get_global_constants($name)    {      foreach ($this->constants as $constant)        {          if ($constant['name'] === $name)            {              return ($constant['location']);            }        }      return (false);    }  private function constants_from_interfaces($interface_name)    {      $results = Array();      try        {          $ro = new ReflectionClass($interface_name);        }      catch (ReflectionException $re)        {          return($results);        }      foreach ($ro->getConstants() as $name => $value)        {          $this->update_global_constants($name, $interface_name);          $location = $this->get_global_constants($name);          $results[] = Array('name' => $name, 'value' => $value, 'location' => $location);        }      return ($results);    }  private function interogate_interfaces($ro)    {      $results = Array();      foreach ($ro->getInterfaceNames() as $in)        {          if (!($this->in_array_r($in, $results)))            {              $constants = $this->constants_from_interfaces($in);              $results[] = Array('name' => $in, 'constants' => $constants);            }        }      asort($results);      return ($results);    }  private function interogate_statics($ro)    {      $results = Array();      foreach ($ro->getStaticProperties() as $name => $value)        {          $results[] = Array('name' => $name, 'value' => $value);        }      return ($results);    }  private function interogate_constants($ro, $class_name)    {      $results = Array();      foreach ($ro->getConstants() as $name => $value)        {          $this->update_global_constants($name, $class_name);          $location = $this->get_global_constants($name);          $results[] = Array('name' => $name, 'value' => $value, 'location' => $location);        }      return ($results);    }  private function interogate_properties($ro)    {      $results = Array();      foreach ($ro->getProperties() as $p)        {          $name = $p->name;          $results[] = Array('name' => $p->name, 'value' => 'todo');        }      return ($results);    }  public function interogate_methods($ro, $name, $parent, $interface)    {      $results              = Array();      $results['local']     = Array();      $results['inherited'] = Array();      foreach ($ro->getMethods() as $m)        {          $local     = $this->check_parent($m->name, (isset($parent['methods']['local']))?$parent['methods']['local']:Array());          $inherited = $this->check_parent($m->name, (isset($parent['methods']['inherited']))?$parent['methods']['inherited']:Array());          $overridden      = 0;          $overridden_from = 0;          if ((($local !== false) || ($inherited !== false)) && ($m->class == $name))            {              $overridden = 1;              if ($local !== false)                {                  $overridden_from = $local['class'];                }              elseif ($inherited !== false)                {                  $overridden_from = $inherited['class'];                }            }          if ($interface)            {              $location = 'local';            }          elseif ($m->class == $name)            {              $location = 'local';            }          else            {              $location = 'inherited';            }          $type = $this->get_type($m);          $inheritable = 0;          if (($m->isProtected()) || ($m->isPublic()))            {              $inheritable = 1;            }          if (($inheritable == 0) && ($location == 'inherited'))            {              // Skip ??            }          else            {              $parameters = Array();              foreach ($m->getParameters() as $p)                {                  if ($p->isOptional())                    {                      $optional = 'Yes';                      try                        {                          $default = $p->getDefaultValue();                        }                      catch (ReflectionException $re)                        {                          $default = 'Built In';                        }                    }                  else                    {                      $optional = 'No';                      $default = 'none';                    }                  $position = $p->getPosition();                  $parameters[] = Array('name' => $p->name, 'optional' => $optional, 'default' => $default, 'position' => $position);                }              $results[$location][] = Array('name' => $m->name, 'class' => $m->class, 'overridden' => $overridden, 'overridden_from' => $overridden_from, 'inheritable' => $inheritable, 'modifier' => $type, 'parameters' => $parameters);            }        }      return ($results);    }  public function interogate_object($name)    {      $results = Array();      try        {          $rc1 = new ReflectionClass($name);        }      catch (ReflectionException $re)        {          return($results);        }      if ($rc1->isInterface())        {          $type = 'interface';          $interface = 1;        }      else        {          $type = 'class';          $interface = 0;        }      $results['name']    = $name;      $results['type']    = $type;      $filename   = $rc1->getFileName();      $start_line = $rc1->getStartLine();      $end_line   = $rc1->getEndLine();      $results['filename'] = ($filename == FALSE)?'Unknown':$filename;      $results['details']  = (($start_line == FALSE) || ($end_line == FALSE))?'Unknown':'Between lines: ' . $start_line . ' and ' . $end_line;      $parent = (array) $rc1->getParentClass();      if (array_key_exists('name', $parent))        {          $parent = $parent['name'];          $results['parent'] = $this->interogate_object($parent);        }      $results['interfaces'] = $this->interogate_interfaces($rc1);      $results['methods'] = $this->interogate_methods($rc1, $name, (isset($results['parent']))?$results['parent']:Array(), $interface);      $results['statics'] = $this->interogate_statics($rc1);      $results['constants'] = $this->interogate_constants($rc1, $name);      $results['properties'] = $this->interogate_properties($rc1);      return ($results);    }}$i = new interogate();//$results = $i->interogate_object('ReflectionClass');$results = $i->interogate_object('c4');print_r($results);?>I am not sure if anyone else has done this already, or if I am making some bad assumptions, but this is my first play with Reflection so this is as much a learning exercise as anything else.The completed class (once complete of course), will be available for free (release GPL v3) for anyone to make use of.
PHP class and interface interrogation using reflection
php;reflection