<?php
/* Test script for the new reflection API
 *
 * Usage:
 * - Test Reflection_Function
 *   php5 reflection.php -f counter
 *
 * - Test Reflection_Class
 *   php5 reflection.php -c counter
 *   php5 reflection.php -c object
 *   php5 reflection.php -c storage
 *   php5 reflection.php -c string
 *   php5 reflection.php -c serializable
 *
 * - Test Reflection_Method
 *   php5 reflection.php -m string concat
 *
 * - Test getConstructor
 *   php5 reflection.php -t string
 *   php5 reflection.php -t object
 *
 * - Test getMethod(s)
 *   php5 reflection.php -d string
 *   php5 reflection.php -d string concat
 *
 * - Test isInstance()
 *   reflection.php -i string
 *   reflection.php -i object
 *
 * - Test newInstance()
 *   php5 reflection.php -n storageimpl [ arg [, arg [ ... ]]]
 *   php5 reflection.php -n exception
 *
 */
 
  /**
   * A simple counter
   *
   * @return    int
   */
  function counter() {
    static $c= 0;
    
    return $c++;
  }
  
  /**
   * Serializable interface
   *
   */
  interface Serializable {
    // TBI
  }
  
  /**
   * Base class
   *
   */
  class Object {
  }
  
  /**
   * A counter class
   *
   * Example:
   * <code>
   *   $c= Counter::count();    // $c is now 0
   *   $c= Counter::count();    // $c is now 1
   * </code>
   */
  class Counter extends Object implements Serializable {
    const START= 0;
    private static $c= Counter::START;
    
    /**
     * Invoke counter
     *
     * @access  public
     * @return  int
     */
    public static function count() {
      return self::$c++;
    }
  }
  
  /**
   * A final class
   *
   */
  final class String {
    private
      $str  = '';

    /**
     * Constructor
     *
     * @access  public
     * @param   string str default '' the initial value
     */
    public function __construct($str= '') {
      $this->str= $str;
    }
    
    /**
     * Concatenate
     *
     * @access  public
     * @param   string str
     */
    public function concat($str) {
      $this->str.= $str;
    }
  }

  /**
   * An abstract class
   *
   */  
  abstract class Storage {
    // TBI
  }

  /**
   * An abstract class
   *
   */  
  class StorageImpl extends Storage {
    function __construct() {
      $a= func_get_args();
      printf("%s(%s)\n", __METHOD__, var_export($a, 1));
    }
  }
  
  // {{{ main
  switch ($argv[1]) {
    case '-f':
      try {
        $func= new Reflection_Function($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }

      var_dump($func);

      printf(
        "===> The %s function '%s'\n".
        "     declared in %s\n".
        "     lines %d to %d\n",
        $func->isInternal() ? 'internal' : 'user-defined',
        $func->getName(),
        var_export($func->getFileName(), 1),
        $func->getStartLine(),
        $func->getEndline()
      );

      printf("---> Documentation:\n %s\n", var_export($func->getDocComment(), 1));

      if ($statics= $func->getStaticVariables()) {
        printf("---> Static variables: %s\n", var_export($statics, 1));
      }

      printf("---> Invokation results in: ");
      var_dump($func->invoke());
      break;
    
    case '-i':
      try {
        $class= new Reflection_Class($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }
      var_dump($class->isInstance(new String()));
      break;

    case '-n':
      try {
        $class= new Reflection_Class($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }
      var_dump($class->newInstance(array_slice($argv, 3)));
      break;

    case '-m':
      try {
        $method= new Reflection_Method($argv[2], $argv[3]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }
      var_dump($method);

      printf(
        "===> The %s%s%s%s%s%s%s method '%s' (which is %s)\n".
        "     declared in %s\n".
        "     lines %d to %d\n".
        "     having the modifiers 0x%x\n",
        $method->isInternal() ? 'internal' : 'user-defined',
        $method->isAbstract() ? ' abstract' : '',
        $method->isFinal() ? ' final' : '',
        $method->isPublic() ? ' public' : '',
        $method->isPrivate() ? ' private' : '',
        $method->isProtected() ? ' protected' : '',
        $method->isStatic() ? ' static' : '',
        $method->getName(),
        $method->isConstructor() ? 'the constructor' : 'a regular method',
        var_export($method->getFileName(), 1),
        $method->getStartLine(),
        $method->getEndline(),
        $method->getModifiers()
      );

      printf("---> Documentation:\n %s\n", var_export($method->getDocComment(), 1));

      if ($statics= $method->getStaticVariables()) {
        printf("---> Static variables: %s\n", var_export($statics, 1));
      }

      printf("---> Invokation results in: ");
      var_dump($method->invoke(new $argv[2]));
      break;

    case '-t':
      try {
        $class= new Reflection_Class($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }
      
      var_dump($class->getConstructor());
      break;

    case '-d':
      try {
        $class= new Reflection_Class($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }
      
      if (isset($argv[3])) {
        var_dump($class->getMethod($argv[3]));
      } else {
        var_dump($class->getMethods());
      }
      break;
 
    case '-c':
      try {
        $class= new Reflection_Class($argv[2]);
      } catch (Exception $e) {
        var_dump($e);
        exit(-1);
      }

      var_dump($class);

      printf(
        "===> The %s%s%s %s '%s' [extends %s]\n".
        "     declared in %s\n".
        "     lines %d to %d\n".
        "     having the modifiers 0x%x\n",
        $class->isInternal() ? 'internal' : 'user-defined',
        $class->isAbstract() ? ' abstract' : '',
        $class->isFinal() ? ' final' : '',
        $class->isInterface() ? 'interface' : 'class',
        $class->getName(),
        var_export($class->getParentClass(), 1),
        var_export($class->getFileName(), 1),
        $class->getStartLine(),
        $class->getEndline(),
        $class->getModifiers()
      );

      printf("---> Documentation:\n %s\n", var_export($class->getDocComment(), 1));
      
      if (!$class->isInterface()) {
        printf("---> Implements:\n %s\n", var_export($class->getInterfaces(), 1));
      }

      if ($constants= $class->getConstants()) {
        printf("---> Constants: %s\n", var_export($constants, 1));
      }

      break;
  }
  // }}}
?>
