PHPonTrax
[ class tree: PHPonTrax ] [ index: PHPonTrax ] [ all elements ]

Source for file shell.php

Documentation is available at shell.php

  1. <?php
  2. /**
  3.  *  (PHP 5)
  4.  *
  5.  *  @package PHPonTrax
  6.  *  @version $Id:$
  7.  *  @copyright (c) 2005 John Peterson
  8.  *
  9.  *   Permission is hereby granted, free of charge, to any person obtaining
  10.  *   a copy of this software and associated documentation files (the
  11.  *   "Software"), to deal in the Software without restriction, including
  12.  *   without limitation the rights to use, copy, modify, merge, publish,
  13.  *   distribute, sublicense, and/or sell copies of the Software, and to
  14.  *   permit persons to whom the Software is furnished to do so, subject to
  15.  *   the following conditions:
  16.  *
  17.  *   The above copyright notice and this permission notice shall be
  18.  *   included in all copies or substantial portions of the Software.
  19.  *
  20.  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21.  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22.  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23.  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24.  *   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25.  *   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26.  *   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27.  */
  28.  
  29. /*
  30. vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
  31. (c) 2006 Jan Kneschke <jan@kneschke.de>
  32.  
  33. Permission is hereby granted, free of charge, to any person obtaining a copy of
  34. this software and associated documentation files (the "Software"), to deal in
  35. the Software without restriction, including without limitation the rights to
  36. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  37. of the Software, and to permit persons to whom the Software is furnished to do
  38. so, subject to the following conditions:
  39.  
  40. The above copyright notice and this permission notice shall be included in all
  41. copies or substantial portions of the Software.
  42.  
  43. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  44. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  45. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  46. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  47. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  48. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  49. SOFTWARE.
  50. */
  51.  
  52. /**
  53. * A interactive PHP Shell
  54. * The more I work with other languages like python and ruby I like their way how they
  55. * work on problems. While PHP is very forgiving on errors, it is weak on the debugging
  56. * side. It was missing a simple to use interactive shell for years. Python and Ruby have
  57. * their ipython and iruby shell which give you a direct way to interact with the objects.
  58. * No need to write a script and execute it afterwards.
  59. * ChangeLog
  60. * Starting the Shell:
  61. * If you have a php-cli at hand you can open the shell by defining 'SHELL'
  62. * and opening the PHP_Shell class file.
  63. * <code>
  64. * $ php -v
  65. * PHP 5.1.4 (cli) (built: May  7 2006 20:52:45)
  66. * Copyright (c) 1997-2006 The PHP Group
  67. * Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies
  68. * $ php -r "define('SHELL', 1); require 'PHP/Shell.php';"
  69. * </code>
  70. * If you only have php-cgi write a php-script:
  71. * <code>
  72. *     error_reporting(E_ALL);
  73. *     define("SHELL", 1);
  74. *     ## in case your terminal support colours:
  75. *     define("SHELL_HAS_COLOUR", 1);
  76. *     require "PHP/Shell.php";
  77. * </code>
  78. * and execute it with:
  79. * <pre>
  80. * $ php -q php-shell.php
  81. * </pre>
  82. * Inline Help
  83. *
  84. * <pre>
  85. * PHP-Shell - Version 0.2.0, with readline() support
  86. * (c) 2006, Jan Kneschke <jan@kneschke.de>
  87. * released under the terms of the PHP License 2.0
  88. * >> use '?' to open the inline help
  89. * >> ?
  90. * "inline help for the PHP-shell
  91. *   >> ?
  92. *     print this help
  93. *   >> ? <topic>
  94. *     get the doccomment for a class, method, property or function
  95. *   >> p <var>
  96. *     execute a verbose print (if implemented)
  97. *   >> quit
  98. *     leave shell
  99. * "
  100. * >> ? PHP_Shell
  101. * </pre>
  102. * Alternatives
  103. * - http://david.acz.org/phpa/
  104. * - http://www.hping.org/phpinteractive/
  105. * - the embedded interactive php-shell: $ php -a
  106. @package PHP
  107. */
  108.  
  109. /**
  110. * PHP_Shell
  111. *
  112. * a interactive PHP Shell with tab-completion and history
  113. * it can catch FATAL errors before executing the code
  114. *
  115. * to customize the operation of the shell you can either
  116. * extend the PHP_Shell class or declare a external autoload
  117. * or error-handler. If you want to use your own print-out
  118. * functions declare __shell_print_vars().
  119. *
  120. * - __shell_error_handler()
  121. * - __autoload()
  122. * - __shell_print_vars()
  123. *
  124. * To keep the namespace clashing between shell and your program
  125. * as small as possible all public variables and functions from
  126. * the shell are prefixed with __shell:
  127. * - $__shell is the object of the shell
  128. *   can be read, this is the shell object itself, don't touch it
  129. * - $__shell_retval is the return value of the eval() before
  130. *   it is printed
  131. *   can't be read, but overwrites existing vars with this name
  132. * - $__shell_exception is the catched Exception on Warnings, Notices, ..
  133. *   can't be read, but overwrites existing vars with this name
  134. @package PHP
  135. */
  136.  
  137. require_once("php_shell/shell_prototypes.php");
  138.  
  139. class PHP_Shell {
  140.     /** 
  141.     * current code-buffer
  142.     * @var string 
  143.     */
  144.     protected $code
  145.  
  146.     /** 
  147.     * set if 'p ...' is executed
  148.     * @var bool 
  149.     */
  150.     protected $verbose
  151.  
  152.     /** 
  153.     * set if readline support is enabled
  154.     * @var bool 
  155.     */
  156.     protected $have_readline
  157.  
  158.     /** 
  159.     * current version of the class
  160.     * @var string 
  161.     */
  162.     protected $version = '0.2.7';
  163.  
  164.     /**
  165.     * registered commands
  166.     *
  167.     * @var array 
  168.     * @see registerCommand
  169.     */
  170.     protected $commands;
  171.  
  172.     /**
  173.     * does the use want to use the internal autoload ?
  174.     *
  175.     * @var bool 
  176.     */
  177.     protected $autoload = false;
  178.     
  179.  
  180.     /**
  181.     * shell colours
  182.     *
  183.     * @var array 
  184.     * @see setColourScheme
  185.     */
  186.     protected $colours;
  187.  
  188.     /**
  189.     * shell colour schemes
  190.     *
  191.     * @var array 
  192.     * @see registerColourScheme
  193.     */
  194.     protected $colour_scheme;
  195.  
  196.     # shell colours
  197.     const C_RESET "\033[0m";
  198.  
  199.     const C_BLACK "\033[0;30m";
  200.     const C_RED "\033[0;31m";
  201.     const C_GREEN "\033[0;32m";
  202.     const C_BROWN "\033[0;33m";
  203.     const C_BLUE "\033[0;34m";
  204.     const C_PURPLE "\033[0;35m";
  205.     const C_CYAN "\033[0;36m";
  206.     const C_LIGHT_GRAY "\033[0;37m";
  207.  
  208.     const C_GRAY "\033[1;30m";
  209.     const C_LIGHT_RED "\033[1;31m";
  210.     const C_LIGHT_GREEN "\033[1;32m";
  211.     const C_YELLOW "\033[1;33m";
  212.     const C_LIGHT_BLUE "\033[1;34m";
  213.     const C_LIGHT_PURPLE "\033[1;35m";
  214.     const C_LIGHT_CYAN "\033[1;36m";
  215.     const C_WHITE "\033[1;37m";
  216.  
  217.     /**
  218.     * init the shell and change if readline support is available
  219.     */ 
  220.     public function __construct({
  221.         $this->code = '';
  222.         $this->vars array();
  223.  
  224.         $this->stdin null;
  225.  
  226.         $this->have_readline = function_exists('readline');
  227.  
  228.         if ($this->have_readline{
  229.             readline_completion_function('__shell_readline_complete');
  230.         }
  231.  
  232.         $this->use_readline true;
  233.  
  234.         $this->commands = array();
  235.  
  236.         $this->registerCommand('#^quit$#''cmdQuit''quit''leaves the shell');
  237.         $this->registerCommand('#^\?$#''cmdHelp''?''show this help');
  238.         $this->registerCommand('#^\? #''cmdHelp''? <var>''show the DocComment a Class, Method or Function'.PHP_EOL.'    e.g.: ? fopen(), ? PHP_Shell, ? $__shell');
  239.         $this->registerCommand('#^p #''cmdPrint''p <var>''print the variable verbosly');
  240.         $this->registerCommand('#^:set #''cmdSet'':set <var>''set a shell variable');
  241.  
  242.         $this->registerColourScheme(
  243.             "plain"array
  244.                 "default"   => """value"     => "",
  245.                 "exception" => """reset"     => ""));
  246.  
  247.         $this->registerColourScheme(
  248.             "dark"array
  249.                 "default"   => PHP_SHELL::C_YELLOW
  250.                 "value"     => PHP_SHELL::C_WHITE,
  251.                 "exception" => PHP_SHELL::C_PURPLE));
  252.  
  253.         $this->registerColourScheme(
  254.             "light"array
  255.                 "default"   => PHP_SHELL::C_BLACK
  256.                 "value"     => PHP_SHELL::C_BLUE,
  257.                 "exception" => PHP_SHELL::C_RED));
  258.  
  259.     }
  260.  
  261.     /**
  262.     * register your own command for the shell
  263.     *
  264.     * @param string $regex a regex to match against the input line
  265.     * @param string $callback a method in this class to call of the regex matches
  266.     * @param string $cmd the command string for the help
  267.     * @param string $help the full help description for this command
  268.     */
  269.     public function registerCommand($regex$callback$cmd$help{
  270.         $this->commands[array(
  271.             'regex' => $regex,
  272.             'method' => $callback,
  273.             'command' => $cmd,
  274.             'description' => $help
  275.         );
  276.     }
  277.     
  278.     /**
  279.     * parse the PHP code
  280.     *
  281.     * we parse before we eval() the code to
  282.     * - fetch fatal errors before they come up
  283.     * - know about where we have to wait for closing braces
  284.     *
  285.     * @return int 0 if a executable statement is in the code-buffer, non-zero otherwise
  286.     */
  287.     public function parse({
  288.         ## remove empty lines
  289.         $this->code = trim($this->code);
  290.         if ($this->code == ''return 1;
  291.  
  292.         $t token_get_all('<?php '.$this->code.' ?>');
  293.   
  294.         $need_semicolon 1/* do we need a semicolon to complete the statement ? */
  295.         $need_return 1;    /* can we prepend a return to the eval-string ? */
  296.         $eval '';          /* code to be eval()'ed later */
  297.         $braces array();   /* to track if we need more closing braces */
  298.  
  299.         $methods array();  /* to track duplicate methods in a class declaration */
  300.         $ts array();       /* tokens without whitespaces */
  301.         
  302.         foreach ($t as $ndx => $token{
  303.             if (is_array($token)) {
  304.                 $ignore 0;
  305.       
  306.                 switch($token[0]{
  307.                 case T_WHITESPACE:
  308.                 case T_OPEN_TAG:
  309.                 case T_CLOSE_TAG:
  310.                     $ignore 1;
  311.                     break;
  312.                 case T_FOREACH:
  313.                 case T_DO:
  314.                 case T_WHILE:
  315.                 case T_FOR:
  316.  
  317.                 case T_IF:
  318.                 case T_RETURN:
  319.                     
  320.                 case T_CLASS:
  321.                 case T_FUNCTION:
  322.                 case T_INTERFACE:
  323.  
  324.                 case T_PRINT:
  325.                 case T_ECHO:
  326.  
  327.                 case T_COMMENT:
  328.                 case T_UNSET:
  329.  
  330.                 case T_INCLUDE:
  331.                 case T_REQUIRE:
  332.                 case T_INCLUDE_ONCE:
  333.                 case T_REQUIRE_ONCE:
  334.                 case T_TRY:
  335.                     $need_return 0;
  336.                     break;
  337.                 case T_VARIABLE:
  338.                 case T_STRING:
  339.                 case T_NEW:
  340.                 case T_EXTENDS:
  341.                 case T_IMPLEMENTS:
  342.                 case T_OBJECT_OPERATOR:
  343.                 case T_DOUBLE_COLON:
  344.                 case T_INSTANCEOF:
  345.  
  346.                 case T_CATCH:
  347.  
  348.                 case T_ELSE:
  349.                 case T_AS:
  350.                 case T_LNUMBER:
  351.                 case T_DNUMBER:
  352.                 case T_CONSTANT_ENCAPSED_STRING:
  353.                 case T_ENCAPSED_AND_WHITESPACE:
  354.                 case T_CHARACTER:
  355.                 case T_ARRAY:
  356.                 case T_DOUBLE_ARROW:
  357.  
  358.                 case T_CONST:
  359.                 case T_PUBLIC:
  360.                 case T_PROTECTED:
  361.                 case T_PRIVATE:
  362.                 case T_ABSTRACT:
  363.                 case T_STATIC:
  364.                 case T_VAR:
  365.  
  366.                 case T_INC:
  367.                 case T_DEC:
  368.                 case T_SL:
  369.                 case T_SL_EQUAL:
  370.                 case T_SR:
  371.                 case T_SR_EQUAL:
  372.  
  373.                 case T_IS_EQUAL:
  374.                 case T_IS_IDENTICAL:
  375.                 case T_IS_GREATER_OR_EQUAL:
  376.                 case T_IS_SMALLER_OR_EQUAL:
  377.                     
  378.                 case T_BOOLEAN_OR:
  379.                 case T_LOGICAL_OR:
  380.                 case T_BOOLEAN_AND:
  381.                 case T_LOGICAL_AND:
  382.                 case T_LOGICAL_XOR:
  383.                 case T_MINUS_EQUAL:
  384.                 case T_PLUS_EQUAL:
  385.                 case T_MUL_EQUAL:
  386.                 case T_DIV_EQUAL:
  387.                 case T_MOD_EQUAL:
  388.                 case T_XOR_EQUAL:
  389.                 case T_AND_EQUAL:
  390.                 case T_OR_EQUAL:
  391.  
  392.                 case T_FUNC_C:
  393.                 case T_CLASS_C:
  394.                 case T_LINE:
  395.                 case T_FILE:
  396.  
  397.                     /* just go on */
  398.                     break;
  399.                 default:
  400.                     /* debug unknown tags*/
  401.                     error_log(sprintf("unknown tag: %d (%s): %s".PHP_EOL$token[0]token_name($token[0])$token[1]));
  402.                     
  403.                     break;
  404.                 }
  405.                 if (!$ignore{
  406.                     $eval .= $token[1]." ";
  407.                     $ts[array("token" => $token[0]"value" => $token[1]);
  408.                 }
  409.             else {
  410.                 $ts[array("token" => $token"value" => '');
  411.  
  412.                 $last count($ts1;
  413.  
  414.                 switch ($token{
  415.                 case '(':
  416.                     /* walk backwards through the tokens */
  417.  
  418.                     if ($last >= &&
  419.                         $ts[$last 1]['token'== T_STRING &&
  420.                         $ts[$last 2]['token'== T_OBJECT_OPERATOR &&
  421.                         $ts[$last 3]['token'== T_VARIABLE {
  422.  
  423.                         /* $object->method( */
  424.  
  425.                         /* $object has to exist and has to be a object */
  426.                         $objname $ts[$last 3]['value'];
  427.                        
  428.                         if (!isset($GLOBALS[ltrim($objname'$')])) {
  429.                             throw new Exception(sprintf('Variable \'%s\' is not set'$objname));
  430.                         }
  431.                         $object $GLOBALS[ltrim($objname'$')];
  432.  
  433.                         if (!is_object($object)) {
  434.                             throw new Exception(sprintf('Variable \'%s\' is not a class'$objname));
  435.                         }
  436.                         
  437.                         $method $ts[$last 1]['value'];
  438.  
  439.                         /* obj */
  440.                         
  441.                         if (!method_exists($object$method)) {
  442.                             throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'"
  443.                                 $objnameget_class($object)$method));
  444.                         }
  445.                     else if ($last >= &&
  446.                         $ts[$last 1]['token'== T_VARIABLE &&
  447.                         $ts[$last 2]['token'== T_OBJECT_OPERATOR &&
  448.                         $ts[$last 3]['token'== T_VARIABLE {
  449.  
  450.                         /* $object->$method( */
  451.  
  452.                         /* $object has to exist and has to be a object */
  453.                         $objname $ts[$last 3]['value'];
  454.                        
  455.                         if (!isset($GLOBALS[ltrim($objname'$')])) {
  456.                             throw new Exception(sprintf('Variable \'%s\' is not set'$objname));
  457.                         }
  458.                         $object $GLOBALS[ltrim($objname'$')];
  459.  
  460.                         if (!is_object($object)) {
  461.                             throw new Exception(sprintf('Variable \'%s\' is not a class'$objname));
  462.                         }
  463.                         
  464.                         $methodname $ts[$last 1]['value'];
  465.  
  466.                         if (!isset($GLOBALS[ltrim($methodname'$')])) {
  467.                             throw new Exception(sprintf('Variable \'%s\' is not set'$methodname));
  468.                         }
  469.                         $method $GLOBALS[ltrim($methodname'$')];
  470.  
  471.                         /* obj */
  472.                         
  473.                         if (!method_exists($object$method)) {
  474.                             throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'"
  475.                                 $objnameget_class($object)$method));
  476.                         }
  477.  
  478.                     else if ($last >= &&
  479.                         $ts[$last 1]['token'== T_STRING &&
  480.                         $ts[$last 2]['token'== T_OBJECT_OPERATOR &&
  481.                         $ts[$last 3]['token'== ']' &&
  482.                             /* might be anything as index */
  483.                         $ts[$last 5]['token'== '[' &&
  484.                         $ts[$last 6]['token'== T_VARIABLE {
  485.  
  486.                         /* $object[...]->method( */
  487.  
  488.                         /* $object has to exist and has to be a object */
  489.                         $objname $ts[$last 6]['value'];
  490.                        
  491.                         if (!isset($GLOBALS[ltrim($objname'$')])) {
  492.                             throw new Exception(sprintf('Variable \'%s\' is not set'$objname));
  493.                         }
  494.                         $array $GLOBALS[ltrim($objname'$')];
  495.  
  496.                         if (!is_array($array)) {
  497.                             throw new Exception(sprintf('Variable \'%s\' is not a array'$objname));
  498.                         }
  499.  
  500.                         $andx $ts[$last 4]['value'];
  501.  
  502.                         if (!isset($array[$andx])) {
  503.                             throw new Exception(sprintf('%s[\'%s\'] is not set'$objname$andx));
  504.                         }
  505.  
  506.                         $object $array[$andx];
  507.  
  508.                         if (!is_object($object)) {
  509.                             throw new Exception(sprintf('Variable \'%s\' is not a class'$objname));
  510.                         }
  511.                         
  512.                         $method $ts[$last 1]['value'];
  513.  
  514.                         /* obj */
  515.                         
  516.                         if (!method_exists($object$method)) {
  517.                             throw new Exception(sprintf("Variable %s (Class '%s') doesn't have a method named '%s'"
  518.                                 $objnameget_class($object)$method));
  519.                         }
  520.  
  521.                     else if ($last >= &&
  522.                         $ts[$last 1]['token'== T_STRING &&
  523.                         $ts[$last 2]['token'== T_DOUBLE_COLON &&
  524.                         $ts[$last 3]['token'== T_STRING {
  525.  
  526.                         /* Class::method() */
  527.  
  528.                         /* $object has to exist and has to be a object */
  529.                         $classname $ts[$last 3]['value'];
  530.                        
  531.                         if (!class_exists($classname)) {
  532.                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist'$classname));
  533.                         }
  534.                         
  535.                         $method $ts[$last 1]['value'];
  536.  
  537.                         if (!in_array($methodget_class_methods($classname))) {
  538.                             throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'"
  539.                                 $classname$method));
  540.                         }
  541.                     else if ($last >= &&
  542.                         $ts[$last 1]['token'== T_VARIABLE &&
  543.                         $ts[$last 2]['token'== T_DOUBLE_COLON &&
  544.                         $ts[$last 3]['token'== T_STRING {
  545.  
  546.                         /* Class::method() */
  547.  
  548.                         /* $object has to exist and has to be a object */
  549.                         $classname $ts[$last 3]['value'];
  550.                        
  551.                         if (!class_exists($classname)) {
  552.                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist'$classname));
  553.                         }
  554.                         
  555.                         $methodname $ts[$last 1]['value'];
  556.  
  557.                         if (!isset($GLOBALS[ltrim($methodname'$')])) {
  558.                             throw new Exception(sprintf('Variable \'%s\' is not set'$methodname));
  559.                         }
  560.                         $method $GLOBALS[ltrim($methodname'$')];
  561.  
  562.                         if (!in_array($methodget_class_methods($classname))) {
  563.                             throw new Exception(sprintf("Class '%s' doesn't have a method named '%s'"
  564.                                 $classname$method));
  565.                         }
  566.  
  567.                     else if ($last >= &&
  568.                         $ts[$last 1]['token'== T_STRING &&
  569.                         $ts[$last 2]['token'== T_NEW {
  570.  
  571.                         /* new Class() */
  572.  
  573.                         $classname $ts[$last 1]['value'];
  574.  
  575.                         if (!class_exists($classname)) {
  576.                             throw new Exception(sprintf('Class \'%s\' doesn\'t exist'$classname));
  577.                         }
  578.  
  579.                         $r new ReflectionClass($classname);
  580.  
  581.                         if ($r->isAbstract()) {
  582.                             throw new Exception(sprintf("Can't instantiate abstract Class '%s'"$classname));
  583.                         }
  584.  
  585.                         if (!$r->isInstantiable()) {
  586.                             throw new Exception(sprintf('Class \'%s\' can\'t be instantiated. Is the class abstract ?'$classname));
  587.                         }
  588.  
  589.                     else if ($last >= &&
  590.                         $ts[0]['token'!= T_CLASS &&
  591.                         $ts[$last 1]['token'== T_STRING &&
  592.                         $ts[$last 2]['token'== T_FUNCTION {
  593.  
  594.                         /* make sure we are not a in class definition */
  595.  
  596.                         /* function a() */
  597.  
  598.                         $func $ts[$last 1]['value'];
  599.  
  600.                         if (function_exists($func)) {
  601.                             throw new Exception(sprintf('Function \'%s\' is already defined'$func));
  602.                         }
  603.                     else if ($last >= &&
  604.                         $ts[0]['token'== T_CLASS &&
  605.                         $ts[1]['token'== T_STRING &&
  606.                         $ts[$last 1]['token'== T_STRING &&
  607.                         $ts[$last 2]['token'== T_FUNCTION {
  608.  
  609.                         /* make sure we are not a in class definition */
  610.  
  611.                         /* class a { .. function a() ... } */
  612.  
  613.                         $func $ts[$last 1]['value'];
  614.                         $classname $ts[1]['value'];
  615.  
  616.                         if (isset($methods[$func])) {
  617.                             throw new Exception(sprintf("Can't redeclare method '%s' in Class '%s'"$func$classname));
  618.                         }
  619.  
  620.                         $methods[$func1;
  621.  
  622.                     else if ($last >= &&
  623.                         $ts[$last 1]['token'== T_STRING {
  624.                         /* func() */
  625.                         $funcname $ts[$last 1]['value'];
  626.                         
  627.                         if (!function_exists($funcname)) {
  628.                             throw new Exception(sprintf("Function %s() doesn't exist"$funcname));
  629.                         }
  630.                     else if ($last >= &&
  631.                         $ts[$last 1]['token'== T_VARIABLE {
  632.     
  633.                         /* $object has to exist and has to be a object */
  634.                         $funcname $ts[$last 1]['value'];
  635.                        
  636.                         if (!isset($GLOBALS[ltrim($funcname'$')])) {
  637.                             throw new Exception(sprintf('Variable \'%s\' is not set'$funcname));
  638.                         }
  639.                         $func $GLOBALS[ltrim($funcname'$')];
  640.  
  641.                         if (!function_exists($func)) {
  642.                             throw new Exception(sprintf("Function %s() doesn't exist"$func));
  643.                         }
  644.  
  645.                     }
  646.                     
  647.                     array_push($braces$token);
  648.                     break;
  649.                 case '{':
  650.                     $need_return 0;
  651.  
  652.                     if ($last >= &&
  653.                         $ts[$last 1]['token'== T_STRING &&
  654.                         $ts[$last 2]['token'== T_CLASS {
  655.  
  656.                         /* class name { */
  657.  
  658.                         $classname $ts[$last 1]['value'];
  659.  
  660.                         if (class_exists($classnamefalse)) {
  661.                             throw new Exception(sprintf("Class '%s' can't be redeclared"$classname));
  662.                         }
  663.                     else if ($last >= &&
  664.                         $ts[$last 1]['token'== T_STRING &&
  665.                         $ts[$last 2]['token'== T_EXTENDS &&
  666.                         $ts[$last 3]['token'== T_STRING &&
  667.                         $ts[$last 4]['token'== T_CLASS {
  668.  
  669.                         /* class classname extends classname { */
  670.  
  671.                         $classname $ts[$last 3]['value'];
  672.                         $extendsname $ts[$last 1]['value'];
  673.  
  674.                         if (class_exists($classnamefalse)) {
  675.                             throw new Exception(sprintf("Class '%s' can't be redeclared"
  676.                                 $classname));
  677.                         }
  678.                         if (!class_exists($extendsnamefalse)) {
  679.                             throw new Exception(sprintf("Can't extend '%s' from not existing Class '%s'"
  680.                                 $classname$extendsname));
  681.                         }
  682.                     else if ($last >= &&
  683.                         $ts[$last 1]['token'== T_STRING &&
  684.                         $ts[$last 2]['token'== T_IMPLEMENTS &&
  685.                         $ts[$last 3]['token'== T_STRING &&
  686.                         $ts[$last 4]['token'== T_CLASS {
  687.  
  688.                         /* class name implements interface { */
  689.  
  690.                         $classname $ts[$last 3]['value'];
  691.                         $implements $ts[$last 1]['value'];
  692.  
  693.                         if (class_exists($classnamefalse)) {
  694.                             throw new Exception(sprintf("Class '%s' can't be redeclared"
  695.                                 $classname));
  696.                         }
  697.                         if (!interface_exists($implementsfalse)) {
  698.                             throw new Exception(sprintf("Can't implement not existing Interface '%s' for Class '%s'"
  699.                                 $implements$classname));
  700.                         }
  701.                     }
  702.  
  703.                     array_push($braces$token);
  704.                     break;
  705.                 case '}':
  706.                     $need_return 0;
  707.                 case ')':
  708.                     array_pop($braces);
  709.                     break;
  710.                 }
  711.                   
  712.                 $eval .= $token;
  713.             }    
  714.         }
  715.  
  716.         $last count($ts1;
  717.         if ($last >= &&
  718.             $ts[$last 0]['token'== T_STRING &&
  719.             $ts[$last 1]['token'== T_DOUBLE_COLON &&
  720.             $ts[$last 2]['token'== T_STRING {
  721.  
  722.             /* Class::constant */
  723.  
  724.             /* $object has to exist and has to be a object */
  725.             $classname $ts[$last 2]['value'];
  726.            
  727.             if (!class_exists($classname)) {
  728.                 throw new Exception(sprintf('Class \'%s\' doesn\'t exist'$classname));
  729.             }
  730.             
  731.             $constname $ts[$last 0]['value'];
  732.  
  733.             $c new ReflectionClass($classname);
  734.             if (!$c->hasConstant($constname)) {
  735.                 throw new Exception(sprintf("Class '%s' doesn't have a constant named '%s'"
  736.                     $classname$constname));
  737.             }
  738.         else if ($last == &&
  739.             $ts[$last 0]['token'== T_VARIABLE {
  740.  
  741.             /* $var */
  742.  
  743.             $varname $ts[$last 0]['value'];
  744.            
  745.             if (!isset($GLOBALS[ltrim($varname'$')])) {
  746.                 throw new Exception(sprintf('Variable \'%s\' is not set'$varname));
  747.             }
  748.         }
  749.  
  750.  
  751.         $need_more count($braces);
  752.         
  753.         if ($need_more || ';' === $token{
  754.             $need_semicolon 0;
  755.         }  
  756.   
  757.         if ($need_return{
  758.             $eval "return ".$eval;
  759.         }
  760.  
  761.         /* add a traling ; if necessary */ 
  762.         if ($need_semicolon$eval .= ';';
  763.         
  764.         if (!$need_more{
  765.             $this->code = $eval;
  766.         }
  767.                 
  768.         return $need_more;
  769.     }
  770.     
  771.     /**
  772.     * show the prompt and fetch a single line
  773.     * 
  774.     * uses readline() if avaialbe
  775.     * 
  776.     * @return string a input-line
  777.     */
  778.     public function readline({
  779.         if (empty($this->code)) print PHP_EOL;
  780.  
  781.         $prompt (empty($this->code)) '>> ' '.. ';
  782.  
  783.         if ($this->have_readline{
  784.             $l readline($prompt);
  785.  
  786.             readline_add_history($l);
  787.         else {
  788.             print $prompt;
  789.  
  790.             if (is_null($this->stdin)) {
  791.                 if (false === ($this->stdin fopen("php://stdin""r"))) {
  792.                     return false;
  793.                 }
  794.             }
  795.             $l fgets($this->stdin);
  796.         }
  797.         return $l;
  798.     }
  799.  
  800.     /**
  801.     * get the inline help
  802.     *
  803.     * @return string the inline help as string
  804.     */
  805.     public function getHelp({
  806.         $o 'Inline Help:'.PHP_EOL;
  807.  
  808.         foreach ($this->commands as $cmd{
  809.             $o .= sprintf('  >> %s'.PHP_EOL.'    %s'.PHP_EOL,
  810.                 $cmd['command'],
  811.                 $cmd['description']
  812.             );
  813.         }
  814.  
  815.         return $o;
  816.     }
  817.  
  818.     /**
  819.     * handle the 'quit' command
  820.     *
  821.     * @return bool false to leave the input() call
  822.     * @see input
  823.     */
  824.     protected function cmdQuit($l{
  825.         return false;
  826.     }
  827.  
  828.     /**
  829.     * handle the 'p ' command
  830.     *
  831.     * set the verbose flag
  832.     *
  833.     * @return string the pure command-string without the 'p ' command
  834.     */
  835.     protected function cmdPrint($l{
  836.         $this->verbose = 1;
  837.         $cmd substr($l2);
  838.  
  839.         return $cmd;
  840.     }
  841.  
  842.     /**
  843.     * handle the '?' commands
  844.     *
  845.     * With the help of the Reflection Class we extract the DocComments and display them
  846.     * For internal Functions we extract the prototype from the php source.
  847.     *
  848.     * ? Class::method()
  849.     * ? $obj->method()
  850.     * ? Class::property
  851.     * ? $obj::property
  852.     * ? Class
  853.     * ? $obj
  854.     * ? function()
  855.     *
  856.     * The license of the PHP_Shell class
  857.     * ? license
  858.     *
  859.     * @return string the help text
  860.     */
  861.     protected function cmdHelp($l{
  862.         if ("? " == substr($l0strlen("? "))) {
  863.             $str substr($l2);
  864.  
  865.             $cmd '';
  866.             
  867.             if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\(\s*\)\s*#'$str$a)) {
  868.                 /* ? Class::method() */
  869.  
  870.                 $class $a[1];
  871.                 $method $a[2];
  872.  
  873.                 if (false !== ($proto PHP_ShellPrototypes::getInstance()->get($class.'::'.$method))) {
  874.  
  875.                     $cmd sprintf("/**\n* %s\n\n* @params %s\n* @return %s\n*/\n",
  876.                         $proto['description'],
  877.                         $proto['params'],
  878.                         $proto['return']
  879.                     );
  880.                 else if (class_exists($classfalse)) {
  881.                     $c new ReflectionClass($class);
  882.  
  883.                     if ($c->hasMethod($method)) {
  884.                         $cmd $c->getMethod($method)->getDocComment();
  885.                     }
  886.                 }
  887.             else if (preg_match('#^\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\(\s*\)\s*#'$str$a)) {
  888.                 /* ? $obj->method() */
  889.                 if (isset($GLOBALS[$a[1]]&& is_object($GLOBALS[$a[1]])) {
  890.                     $class get_class($GLOBALS[$a[1]]);
  891.                     $method $a[2];
  892.                     
  893.                     $c new ReflectionClass($class);
  894.     
  895.                     if ($c->hasMethod($method)) {
  896.                         $cmd $c->getMethod($method)->getDocComment();
  897.                     }
  898.                 }
  899.             else if (preg_match('#^([A-Za-z0-9_]+)::([a-zA-Z0-9_]+)\s*$#'$str$a)) 
  900.                 /* ? Class::property */
  901.                 $class $a[1];
  902.                 $property $a[2];
  903.                 if (class_exists($classfalse)) {
  904.                     $c new ReflectionClass($class);
  905.  
  906.                     if ($c->hasProperty($property)) {
  907.                         $cmd $c->getProperty($property)->getDocComment();
  908.                     }
  909.                 }
  910.             else if (preg_match('#^\$([A-Za-z0-9_]+)->([a-zA-Z0-9_]+)\s*$#'$str$a)) 
  911.                 /* ? $obj->property */
  912.                 if (isset($GLOBALS[$a[1]]&& is_object($GLOBALS[$a[1]])) {
  913.                     $class get_class($GLOBALS[$a[1]]);
  914.                     $method $a[2];
  915.                     
  916.                     $c new ReflectionClass($class);
  917.  
  918.                     if ($c->hasProperty($property)) {
  919.                         $cmd $c->getProperty($property)->getDocComment();
  920.                     }
  921.  
  922.                 }
  923.             else if (preg_match('#^([A-Za-z0-9_]+)$#'$str$a)) {
  924.                 /* ? Class */
  925.                 if (class_exists($a[1]false)) {
  926.                     $c new ReflectionClass($a[1]);
  927.                     $cmd $c->getDocComment();
  928.                 else if ($a[1== 'license'{
  929.                     $cmd = <<<EOF
  930. (c) 2006 Jan Kneschke <jan@kneschke.de>
  931.  
  932. Permission is hereby grantedfree of chargeto any person obtaining a copy of
  933. this software and associated documentation files (the "Software"), to deal in
  934. the Software without restrictionincluding without limitation the rights to
  935. usecopymodifymergepublishdistributesublicenseand/or sell copies
  936. of the Softwareand to permit persons to whom the Software is furnished to do
  937. sosubject to the following conditions:
  938.  
  939. The above copyright notice and this permission notice shall be included in all
  940. copies or substantial portions of the Software.
  941.  
  942. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KINDEXPRESS OR
  943. IMPLIEDINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  944. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENTIN NO EVENT SHALL THE
  945. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIMDAMAGES OR OTHER
  946. LIABILITYWHETHER IN AN ACTION OF CONTRACTTORT OR OTHERWISEARISING FROM,
  947. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  948. SOFTWARE.
  949.  
  950. EOF;
  951.                 }
  952.             else if (preg_match('#^\$([A-Za-z0-9_]+)$#'$str$a)) {
  953.                 /* ? $object */
  954.                 $obj $a[1];
  955.                 if (isset($GLOBALS[$obj]&& is_object($GLOBALS[$obj])) {
  956.                     $class get_class($GLOBALS[$obj]);
  957.  
  958.                     $c new ReflectionClass($class);
  959.                     $cmd $c->getDocComment();
  960.                 }
  961.  
  962.             else if (preg_match('#^([A-Za-z0-9_]+)\(\s*\)$#'$str$a)) {
  963.                 /* ? function() */
  964.                 $func $a[1];
  965.  
  966.                 if (false !== ($proto PHP_ShellPrototypes::getInstance()->get($func))) {
  967.                     $cmd sprintf("/**\n* %s\n*\n* @params %s\n* @return %s\n*/\n",
  968.                         $proto['description'],
  969.                         $proto['params'],
  970.                         $proto['return']
  971.                     );
  972.                 else if (function_exists($func)) {
  973.                     $c new ReflectionFunction($func);
  974.                     $cmd $c->getDocComment();
  975.                 }
  976.             }
  977.  
  978.             if ($cmd == ''{
  979.                 $cmd var_export(sprintf('no help found for \'%s\''$str)1);
  980.             else {
  981.                 $cmd var_export($cmd1);
  982.             }
  983.         else if ("?" == $l{
  984.             $cmd $this->getHelp();
  985.             $cmd var_export($cmd1);
  986.         }
  987.  
  988.         return $cmd;
  989.     }
  990.  
  991.     /**
  992.     * set a shell-var
  993.     *
  994.     * :set al to enable autoload
  995.     * :set bg=dark to enable highlighting with a dark backgroud
  996.     */
  997.     public function cmdSet($l{
  998.         if (!preg_match('#:set\s+([a-z]+)\s*(?:=\s*([a-z0-9]+)\s*)?$#i'$l$a)) {
  999.             print('unknown :set syntax');
  1000.             return;
  1001.         }
  1002.  
  1003.         $key $a[1];
  1004.  
  1005.         switch ($key{
  1006.         case 'bg':
  1007.         case 'background':
  1008.             if (!isset($a[2])) {
  1009.                 print(':set '.$key.' failed: a value is required, example: :set '.$key.'=dark');
  1010.                 return;
  1011.             }
  1012.             if (false == $this->applyColourScheme($a[2])) {
  1013.                 print('setting colourscheme failed: colourscheme '.$a[2].' is unknown');
  1014.                 return;
  1015.             }
  1016.             break;
  1017.         case 'al':
  1018.         case 'autoload':
  1019.             if (function_exists('__autoload')) {
  1020.                 print('can\'t enabled autoload as a external __autoload() function is already defined');
  1021.                 return;
  1022.             }
  1023.  
  1024.             if ($this->autoload{
  1025.                 print('autload is already enabled');
  1026.                 return;
  1027.             }
  1028.  
  1029.             $this->autoload = true;
  1030.             break;
  1031.         default:
  1032.             print (':set '.$key.' failed: unknown key');
  1033.             return;
  1034.         }
  1035.     }
  1036.     
  1037.     /**
  1038.     * handle the input line
  1039.     *
  1040.     * read the input and handle the commands of the shell
  1041.     *
  1042.     * @return bool false on 'quit' or EOF, true otherwise
  1043.     */
  1044.     public function input({
  1045.         $l $this->readline();
  1046.  
  1047.         /* got EOF ? */
  1048.         if (false === $lreturn false;
  1049.  
  1050.         $l trim($l);
  1051.         
  1052.         if (empty($this->code)) {
  1053.             $this->verbose = 0;
  1054.  
  1055.             foreach ($this->commands as $cmd{
  1056.                 if (preg_match($cmd['regex']$l)) {
  1057.                     $func $cmd['method'];
  1058.  
  1059.                     if (false === ($l $this->$func($l))) {
  1060.                         ## quit
  1061.                         return false;
  1062.                     }
  1063.                     break;
  1064.                 }
  1065.             }
  1066.         }
  1067.        
  1068.         $this->appendCode($l)
  1069.  
  1070.         return true;
  1071.     }
  1072.  
  1073.     public function isAutoloadEnabled({
  1074.         return $this->autoload;
  1075.     }
  1076.     
  1077.     /**
  1078.     * get the code-buffer
  1079.     * 
  1080.     * @return string the code-buffer
  1081.     */
  1082.     public function getCode({
  1083.         return $this->code;
  1084.     }
  1085.     
  1086.     /**
  1087.     * reset the code-buffer
  1088.     */
  1089.     public function resetCode({
  1090.         $this->code = '';
  1091.     }
  1092.  
  1093.     /**
  1094.     * append code to the code-buffer
  1095.     *
  1096.     * @param string $code input buffer
  1097.     */
  1098.     public function appendCode($code{
  1099.         $this->code .= $code;
  1100.     }
  1101.    
  1102.     /**
  1103.     * check if we have a verbose print-out
  1104.     *
  1105.     * @return bool 1 if verbose, 0 otherwise
  1106.     */
  1107.     public function getVerbose({
  1108.         return $this->verbose;
  1109.     }
  1110.  
  1111.     /**
  1112.     * check if readline support is enabled
  1113.     *
  1114.     * @return bool true if enabled, false otherwise
  1115.     */
  1116.     public function hasReadline({
  1117.         return $this->have_readline;
  1118.     }
  1119.  
  1120.     /**
  1121.     * get version of the class
  1122.     *
  1123.     * @return string version-string
  1124.     */
  1125.     public function getVersion({
  1126.         return $this->version;
  1127.     }
  1128.  
  1129.     /**
  1130.     * get a colour for the shell
  1131.     *
  1132.     * @param string $type one of (value|exception|reset|default)
  1133.     * @return string a colour string or a empty string
  1134.     */
  1135.     public function getColour($type{
  1136.         return isset($this->colour[$type]$this->colour[$type'';
  1137.     }
  1138.  
  1139.     /**
  1140.     * apply a colour scheme to the current shell
  1141.     *
  1142.     * @param string $scheme name of the scheme
  1143.     * @return false if colourscheme is not known, otherwise true
  1144.     */
  1145.     public function applyColourScheme($scheme{
  1146.         if (!isset($this->colour_scheme[$scheme])) return false;
  1147.  
  1148.         $this->colour $this->colour_scheme[$scheme];
  1149.  
  1150.         return true;
  1151.     }
  1152.  
  1153.     /**
  1154.     * registers a colour scheme
  1155.     *
  1156.     * @param string $scheme name of the colour scheme
  1157.     * @param array a array of colours
  1158.     */
  1159.     public function registerColourScheme($scheme$colours{
  1160.         if (!is_array($colours)) return;
  1161.  
  1162.         /* set a reset colour if it is not supplied from the outside */
  1163.         if (!isset($colours["reset"])) $colours["reset"PHP_SHELL::C_RESET;
  1164.  
  1165.         $this->colour_scheme[$scheme$colours;
  1166.     }
  1167. }
  1168.  
  1169. /**
  1170. * a readline completion callback
  1171. *
  1172. @param string $str linebuffer
  1173. @param integer $pos position in linebuffer
  1174. @return array list of possible matches
  1175. */
  1176. function __shell_readline_complete($str$pos{
  1177.     $in readline_info('line_buffer');
  1178.  
  1179.     /**
  1180.     * parse the line-buffer backwards to see if we have a 
  1181.     * - constant
  1182.     * - function 
  1183.     * - variable
  1184.     */
  1185.  
  1186.     $m array();
  1187.  
  1188.     if (preg_match('#\$([A-Za-z0-9_]+)->#'$in$a)) {
  1189.         /* check for $o->... */
  1190.         $name $a[1];
  1191.  
  1192.         if (isset($GLOBALS[$name]&& is_object($GLOBALS[$name])) {
  1193.             $c get_class_methods($GLOBALS[$name]);
  1194.  
  1195.             foreach ($c as $v{
  1196.                 $m[$v.'(';
  1197.             }
  1198.             $c get_class_vars(get_class($GLOBALS[$name]));
  1199.  
  1200.             foreach ($c as $k => $v{
  1201.                 $m[$k;
  1202.             }
  1203.  
  1204.             return $m;
  1205.         }
  1206.     else if (preg_match('#\$([A-Za-z0-9_]+)\[([^\]]+)\]->#'$in$a)) {
  1207.         /* check for $o[...]->... */
  1208.         $name $a[1];
  1209.  
  1210.         if (isset($GLOBALS[$name]&& 
  1211.             is_array($GLOBALS[$name]&&
  1212.             isset($GLOBALS[$name][$a[2]])) {
  1213.  
  1214.             $c get_class_methods($GLOBALS[$name][$a[2]]);
  1215.  
  1216.             foreach ($c as $v{
  1217.                 $m[$v.'(';
  1218.             }
  1219.             $c get_class_vars(get_class($GLOBALS[$name][$a[2]]));
  1220.  
  1221.             foreach ($c as $k => $v{
  1222.                 $m[$k;
  1223.             }
  1224.             return $m;
  1225.         }
  1226.  
  1227.     else if (preg_match('#([A-Za-z0-9_]+)::#'$in$a)) {
  1228.         /* check for Class:: */
  1229.         $name $a[1];
  1230.  
  1231.         if (class_exists($namefalse)) {
  1232.             $c get_class_methods($name);
  1233.  
  1234.             foreach ($c as $v{
  1235.                 $m[sprintf('%s::%s('$name$v);
  1236.             }
  1237.  
  1238.             $cl new ReflectionClass($name);
  1239.             $c $cl->getConstants();
  1240.  
  1241.             foreach ($c as $k => $v{
  1242.                 $m[sprintf('%s::%s'$name$k);
  1243.             }
  1244.  
  1245.             return $m;
  1246.         }
  1247.     else if (preg_match('#\$([a-zA-Z]?[a-zA-Z0-9_]*)$#'$in)) {
  1248.         $m array_keys($GLOBALS);
  1249.  
  1250.         return $m;
  1251.     else if (preg_match('#new #'$in)) {
  1252.         $c get_declared_classes();
  1253.     
  1254.         foreach ($c as $v{
  1255.             $m[$v.'(';
  1256.         }
  1257.  
  1258.         return $m;
  1259.     else if (preg_match('#^:set #'$in)) {
  1260.         $m['autoload';
  1261.         $m['background=';
  1262.  
  1263.         return $m;
  1264.     }
  1265.  
  1266.     $f get_defined_functions();
  1267.  
  1268.     foreach ($f['internal'as $v{
  1269.         $m[$v.'(';
  1270.     }
  1271.  
  1272.     foreach ($f['user'as $v{
  1273.         $m[$v.'(';
  1274.     }
  1275.     
  1276.     $c get_declared_classes();
  1277.  
  1278.     foreach ($c as $v{
  1279.         $m[$v.'::';
  1280.     }
  1281.  
  1282.     $c get_defined_constants();
  1283.  
  1284.     foreach ($c as $k => $v{
  1285.         $m[$k;
  1286.     }
  1287.  
  1288.     $m['foreach (';
  1289.     $m['require';
  1290.  
  1291.     # printf("%s ... %s\n", $str, $pos);
  1292.     return $m;
  1293. }

Documentation generated on Mon, 21 May 2007 22:28:55 -0600 by phpDocumentor 1.3.2