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