Php/PhpSimpleParser

From Php-Classes

Jump to: navigation, search


[edit] Php_Simple_Parser

[edit] class usage

Here is a basic usage for this class parser :

   $file = __FILE__;
   $args = $_SERVER['argv'];
   if(count($args) > 1)
   
   $file = $args[1];
   
   # create a new php parser
   $parser = new Php_Parser_Simple();
   
   $start = microtime(true);
   
   	# parse a php-file and return an object that handle php declarations
   	$php_main_block = $parser->parse_file($file);
   	
   		# get declared classes
   		$classes = $php_main_block->get_classes();
   	
   		# and display methods and attributes.
   		foreach($classes as $class){
   			printf("class %s (%d:%s)\n", $class->name(), $class->line(), $class->file());
   	
   			foreach($class->attributes() as $attr)
   				printf("    %s\n", $attr->to_text());
   
   			foreach($class->methods() as $meth)
   				printf("    %s\n", $meth->to_text());
   
   			# should do the same :
   			# echo $class->to_text($full_print=true, $sort=true);
   
   		}

[edit] complete source code

   <?php
   
   error_reporting(E_ALL);
   
   
   /**
   
   	author : Marc Quinton - january 2007.
   	licence : LGPL
   
   	a simple php parser ; can be used for a  PHP IDE to browse classe tree with methods and attributes.
   
   	- usage : see at the bottom of file.
   	- documentation : to be done.
   
   
   	this parser is partial :
   	- it does not handle very right argument list
   	- does not know any thing about method body,
   	- does not handle global scope variables and functions
   	- methods and attributes options (private, protected, virtual) need to be writen if need ; token are ready to use
   
   	Notes :
   	- this parser is heavy based on php tokenizer : http://www.php.net/manual/en/ref.tokenizer.php
   	- there is some other parser for php but not working correctly with php5.
   	- all classes are prefixed with Php_Parser_Simple except main class whose name is Php_Parser_Simple to avaoid class name conflits
   	- classes are used for :
   		- container classes (stacks)
   		- php attributes containers for class, methods and attributes :
   			- Php_Parser_Simple_ClassBlock
   			- Php_Parser_Simple_MethodDecl
   			- Php_Parser_Simple_AttributeDecl
   		- to handle tokens from php tokenizer
   
   	benchmarks :
   		- 3Ghz CPU,
   		- runs in 128ms for this file without printf :
   			- 21 classes,
   			- 76 methods
   
   	bugs :
   		- function arguments with default value ($xx=123) not correctly handeled : 
   			foobar($v1, $v2=123) is seen as function foobar($v1, $v2, 123)
   
   	todo:
   		- redesign class tree and class name for this parser :
   			- there is block, stack, declarations, tokens classes
   			- may be confusing.
   		- handle methods and attributes options (private, protected, virtual)
   		- handle methods body,
   		- handle global scope function and variables
   		- handle class tree (extends keyword)
   		- handle include, require keyword
   		- parse comment for documentation extraction.
   		- build a nice GUI for php-gtk.
   
   	basic usage :
   
   		# create a new php parser
   		$parser = new Php_Parser_Simple();
   		
   		
   			# parse a php-file and return an object that handle php declarations
   			$php_main_block = $parser->parse_file($file);
   			
   				# get declared classes
   				$classes = $php_main_block->get_classes();
   			
   				# and display methods and attributes.
   				foreach($classes as $class){
   					printf("class %s (%d:%s)\n", $class->name(), $class->line(), $class->file());
   					# echo $class->to_text() . "\n";
   		
   					foreach($class->methods() as $meth)
   						printf("    %s\n", $meth->to_text());
   			
   					foreach($class->attributes() as $attr)
   						printf("    %s\n", $attr->to_text());
   				}
   
   
   	Synopsis for main classes (in logical usage order) :
   
   	* Php_Parser_Simple
   		- __construct() with no args,
   		- parse_source($php_source) ; returns a Php_Parser_Simple_MainBlock
   
   	* Php_Parser_Simple_MainBlock
   		- do not __construct this class ; objects are create from Php_Parser_Simple
   		- get_classes(sort=false) : return an array of classes (Php_Parser_Simple_ClassBlock)
   
   	* Php_Parser_Simple_ClassBlock
   		- do not __construct this class ; objects are create from Php_Parser_Simple
   		- methods($sort=true) : lists methods for this class ; ; returns a list of attributes as a list of Php_Parser_Simple_MethodDecl
   		- attributes($sort=true) : lists attributes ; returns a list of attributes as a list of Php_Parser_Simple_AttributeDecl
   		- to_text($full_print=false, $sort=false) ; usefull for debugging
   		- name() : returns class name,
   		- line(), file() : returns where this class is located in php source code
   
   	* Php_Parser_Simple_MethodDecl
   	* Php_Parser_Simple_AttributeDecl
   		- do not __construct this class ; objects are create from Php_Parser_Simple
   		- to_text() : for debugging
   		- name : returns (method|atribute) name,
   		- line(), file() : returns where this (method|class) is located in php source code
   
   	all other classes are for internal use.
   
   
   	links :
   
   	- parser :
   		http://pear.php.net/package/PHP_Parser
   		http://greg.chiaraquartet.net/archives/137-a-parser-generator-for-PHP-finally.html
   		http://pear.chiaraquartet.net/PHP_ParserGenerator/PHP_ParserGenerator/_ParserGenerator.php.html
   		http://pear.chiaraquartet.net/lemon/
   		http://netevil.org/node.php?nid=941
   		http://www.hwaci.com/sw/lemon/lemon.html
   
   */
   
   
   /**
   * here we need to build different list (stacks)
   *
   *	- Stack (core stack methods)
   *	- Block
   *	- TokenList
   *	- StatementBlock 
   *	- PhpBlock
   *	- ParamBlock
   *
   * Notes :
   *	- may be some are unused.
   *	- typed list are very conveniant with print_r(), perhaps they are not really needed (mandatory) for this parser.
   */
   class Php_Parser_Simple_Stack{
   
   	protected $data;
   	protected $index;	#iterator index
   
   	function __construct(){
   		$this->data = array();
   		$this->index = 0;
   	}
   
   	public function push($data){
   		$this->data[] = $data;
   	}
   
   	public function add($data){
   		$this->data[] = $data;
   	}
   
   	public function pop(){
   		return array_pop($this->data);
   	}
   
   	public function next(){
   		if(isset($this->data[$this->index]))
   			return $this->data[$this->index++];
   		return null;
   	}
   
   	public function has_next(){
   		if($this->index < count($this->data))
   			return true;
   		return false;
   	}
   	public function reset(){
   		$this->index = 0;
   	}
   
   	function to_text(){
   		return sprintf("block - Stack(%s)", count($this->data));
   	}
   
   	function text(){
   		return ;
   	}
   
   	function find($name){
   
   		$list = array();
   
   		foreach($this->data as $obj)
   			if($obj->text() == $name)
   				$list[] = $obj;
   
   		return $list;
   	}
   }
   
   class Php_Parser_Simple_TokenList extends Php_Parser_Simple_Stack{
   
   }
   
   class Php_Parser_Simple_Block extends Php_Parser_Simple_Stack{
   
   }
   
   class Php_Parser_Simple_StatementBlock extends Php_Parser_Simple_Stack{
   
   }
   
   class Php_Parser_Simple_PhpBlock extends Php_Parser_Simple_Block{
   
   	protected $level;
   
   	public function __construct($level){
   		$this->level = $level;
   		parent::__construct();
   	}
   
   	public function level(){
   		return $this->level;
   	}
   
   	function to_text($level = 0){
   
   
   		$level = $this->level;
   		$sub_level = max(0,$this->level-1);
   		$indent = str_repeat('    ', $level);
   		$sub_indent = str_repeat('    ', $sub_level);
   
   		$text = "{\n$indent";
   
   		while($this->has_next()){
   			$token = $this->next();
   
   			if(is_a($token, 'Php_Parser_Simple_TextToken') && $token->text() == ';')
   				$text .= ";\n$indent";
   
   			elseif(is_a($token, 'Php_Parser_Simple_PhpBlock'))
   				$text .= $token->to_text();
   			else
   				$text .= $token->to_text() . ' ';
   
   		}
   
   		$text .= "\n$sub_indent}\n$sub_indent";
   		return $text;
   	}
   }
   
   class Php_Parser_Simple_ParamBlock extends Php_Parser_Simple_Block{
   
   	public function to_text(){
   		if(count($this->data) > 0){
   
   			foreach($this->data as $obj)
   				$list[] = $obj->to_text();
   
   			$txt = join(', ', $list);
   			# fixme : function($var=123) is not supported ; returns function($var,123)
   			return "($txt)";
   		}
   		else
   			return '()';
   	}
   }
   
   class Php_Parser_Simple_Declaration {
   	protected $name;
   	protected $options;
   	protected $token;
   	protected $type = null;
   
   	public function name(){
   		return $this->name;
   	}
   	public function line(){
   		return $this->token->line();
   	}
   	public function file(){
   		return $this->token->file();
   	}
   
   	function to_text(){
   		return sprintf('%s - (%d:%s)', $this->name(), $this->line(), $this->file());
   	}
   }
   
   class Php_Parser_Simple_MethodDecl extends Php_Parser_Simple_Declaration{
   	protected $args;
   	protected $body;
   
   	function __construct($name, $options, $args, $body, $token){
   		$this->type = "method";
   		$this->name = $name;
   		$this->options = $options;
   		$this->args = $args;
   		$this->body = $body;
   		$this->token = $token;
   	}
   	function to_text(){
   		return sprintf('%s() - (%d:%s)', $this->name(), $this->line(), $this->file());
   	}
   }
   
   class Php_Parser_Simple_AttributeDecl extends Php_Parser_Simple_Declaration{
   
   	function __construct($name, $options,$token){
   		$this->type = "attribute";
   		$this->name = $name;
   		$this->options = $options;
   		$this->token = $token;
   	}
   }
   
   
   /**
   * ClassBlock :
   *
   *	- handle class attributes
   *	- internaly, parse class tokens (parse_body())
   *
   *
   */
   class Php_Parser_Simple_ClassBlock extends Php_Parser_Simple_Block{
   	protected $name;
   	protected $options;
   	protected $body;
   	protected $token;
   
   	function __construct($name, $options, $body, $token){
   		$this->name = $name;
   		$this->options = $options;
   		$this->body = $body;
   		$this->token = $token;
   
   		$this->body = $this->parse_body();
   	}
   
   	function to_text($full_print=false, $sort=false){
   		if(!$full_print)
   			return sprintf("class %s (%d:%s)", $this->name(), $this->line(), $this->file());
   		
   		$txt = $this->to_text(false) . "\n";
   
   		foreach($this->attributes($sort) as $attr)
   			$txt .= "    - " . $attr->to_text() . "\n";
   
   		foreach($this->methods($sort) as $meth)
   			$txt .= "    - " . $meth->to_text() . "\n";
   
   		return $txt;
   	}
   
   	public function name(){
   		return $this->name;
   	}
   
   	public function line(){
   		return $this->token->line();
   	}
   
   	public function file(){
   		return $this->token->file();
   	}
   
   	public function methods($sort=true){
   		$list = array();
   		$this->body->reset();
   
   		while($this->body->has_next()){
   			$obj = $this->body->next();
   			if(is_a($obj, 'Php_Parser_Simple_MethodDecl'))
   				$list[$obj->name()] = $obj;
   		}
   
   		if($sort)
   			ksort($list);
   
   		return $list;
   	}
   
   	public function attributes($sort=true){
   		$list = array();
   		$this->body->reset();
   
   		while($this->body->has_next()){
   			$obj = $this->body->next();
   			if(is_a($obj, 'Php_Parser_Simple_AttributeDecl'))
   				$list[$obj->name()] = $obj;
   		}
   
   		if($sort)
   			ksort($list);
   
   		return $list;
   	}
   
   	/**
   	* given a list of tokens for a php class, try to detect 
   	*	- class attributes with declarations
   	*	- class methods with attributes, arguments and body
   	*/
   	protected function parse_body(){
   
   		$data = new Php_Parser_Simple_PhpBlock($level_fixme=0);  # fixme : we lost block level here
   		$statement = array();
   		$options = array();
   		$decl = array();
   		$option_list = array(T_PROTECTED, T_PUBLIC, T_PRIVATE, T_ABSTRACT);
   
   		while($this->body->has_next()){
   			$token = $this->body->next();
   			if(is_a($token, 'Php_Parser_Simple_TextToken') && $token->text() == ';'){
   				# this is an end of statement (block)
   
   				$name = $decl[0]->text();
   				$data->add($attr = new Php_Parser_Simple_AttributeDecl($name, $options, $decl[0]));
   
   				# reset context
   				$statement = array();
   				$options = array();
   				$decl = array();
   
   			}elseif(is_a($token, 'Php_Parser_Simple_PhpToken') && $token->id() == T_VARIABLE){
   				# this is a (class) attribute declaration
   				$decl[] = $token;
   			}elseif(is_a($token, 'Php_Parser_Simple_PhpToken') && $token->id() == T_FUNCTION){
   				# this is a (class) attribute declaration
   				$name = $this->body->next()->text();
   				$args = $this->body->next();
   				$body = $this->body->next();
   				$data->add($meth = new Php_Parser_Simple_MethodDecl($name, $options, $args, $body, $token));
   
   				# reset context
   				$statement = array();
   				$options = array();
   				$decl = array();
   
   			} elseif(is_a($token, 'Php_Parser_Simple_PhpToken') && in_array($token->id(), $option_list))
   				$options[] = $token;
   			else
   				$statement[] = $token;
   		}
   
   		return $data;
   	}
   }
   
   /**
   * a class to handle global scope for a list of PhpTokens
   *
   */
   class Php_Parser_Simple_MainBlock extends Php_Parser_Simple_PhpBlock{
   
   	public function __construct($level=0){
   		$this->level = $level;
   		parent::__construct(0);
   	}
   
   	public function get_classes($sort=true){
   		$classes = array();
   		$this->reset();
   		while($this->has_next()){
   			$token = $this->next();
   			if(is_a($token, 'Php_Parser_Simple_ClassBlock')){
   				$classes[$token->name()] = $token;
   			}
   		}
   
   		if($sort)
   			ksort($classes);
   
   		return $classes;
   	}
   }
   
   /**
   * below : a list of class to handle token attributes :
   *
   *	- PhpToken
   *	- SimpleToken
   *	- ScalarToken
   *	- TextToken
   *	- CommentToken
   *	- SpacingToken
   *	- NullToken
   */
   class Php_Parser_Simple_PhpToken{
   
   	protected $id;          # token ID as in http://www.php.net/manual/en/tokens.php
   	protected $text;        # token content
   	protected $block_level; # block level : change with { and } match
   
   	protected $line;
   	protected $col;
   	protected $file;
   	protected $name;  # for debug un print_r()
   
   	public function __construct($id, $text, $level, $line=null, $col=null, $file=null){
   		$this->id = $id;
   		$this->text = $text;
   		$this->block_level = $level;
   		$this->line = $line;
   		$this->col = $col;
   		$this->file = $file;
   		$this->name = $this->name();  # debug
   	}
   
   	public function to_text(){
   		return $this->text;
   	}
   	public function debug(){
   		return sprintf('%d:%d - %s: %s (%d)', $this->line, $this->col, $this->name(), $this->text, $this->block_level);
   	}
   
   	public function name(){
   		return token_name($this->id);
   	}
   
   	public function id(){
   		return $this->id;
   	}
   
   	public function line(){
   		return $this->line;
   	}
   
   	public function file(){
   		return $this->file;
   	}
   
   	public function text(){
   		return $this->text;
   	}
   }
   
   # simple token (textual)
   class Php_Parser_Simple_SimpleToken  extends Php_Parser_Simple_PhpToken{
   	public function __construct($id, $text, $level, $line=null, $col=null, $file=null){
   		$this->id = null;
   		$this->text = $text;
   		$this->block_level = $level;
   		$this->line = $line;
   		$this->col = $col;
   		$this->file = $file;
   		$this->line_count = substr_count($text, "\n");  # debug
   	}
   	public function to_text(){
   		if($this->text == ';')
   			return ";\n";
   		return $this->text;
   	}
   	public function debug(){
   		return sprintf('%d - text-token : "%s"', $this->line, $this->text);
   	}
   }
   
   class Php_Parser_Simple_ScalarToken  extends Php_Parser_Simple_SimpleToken{
   
   	public function to_text(){
   		return $this->text;
   	}
   }
   
   
   # simple token (textual)
   class Php_Parser_Simple_TextToken  extends Php_Parser_Simple_SimpleToken{
   }
   
   class Php_Parser_Simple_CommentToken  extends Php_Parser_Simple_TextToken{
   }
   class Php_Parser_Simple_SpacingToken  extends Php_Parser_Simple_TextToken{
   }
   
   
   # uninteresting Token
   class Php_Parser_Simple_NullToken  extends Php_Parser_Simple_SimpleToken{
   }
   
   /*
   * T_ML_COMMENT does not exist in PHP 5.
   * The following three lines define it in order to
   * preserve backwards compatibility.
   *
   * The next two lines define the PHP 5 only T_DOC_COMMENT,
   * which we will mask as T_ML_COMMENT for PHP 4.
   */
   if (!defined('T_ML_COMMENT')) {
   define('T_ML_COMMENT', T_COMMENT);
   } else {
   define('T_DOC_COMMENT', T_ML_COMMENT);
   }
   
   
   /**
   
   	Php_Parser_Simple - the main class for this package.
   
   */
   class Php_Parser_Simple{
   
   	protected $file;
   
   	protected $line;
   	protected $col;
   	protected $block_level;
   
   	protected $tokens;
   
   
   	function __construct(){
   		if(!function_exists('token_get_all'))
   			throw new Exception ('function token_get_all() not found : see http://www.php.net/manual/en/ref.tokenizer.php');
   	}
   
   	protected function initialize(){
   		$this->line = 1;
   		$this->col  = 1;
   		$this->block_level=0;
   		$this->tokens = array();
   	}
   
   	public function parse_source($source, $file=){
   
   		$this->initialize();
   
   		# get a list of tokens from php tokenizer.
   		$token_list = $this->get_tokens($source, $file);
   
   		# list of tokens is a flat list : try to parse block and build a tree of tokens for easy parsing.
   		$php_main_block = $this->tokens_parse_blocks($token_list);
   
   		# parse tokens and detect class declarations with methods and attributes.
   		$php_main_block = $this->tokens_parse_class_blocks($php_main_block);
   
   		return $php_main_block;
   	}
   
   	public function parse_file($file){
   
   		$this->initialize();
   
   		# read source file.
   		$source = file_get_contents($file);
   
   		# return a tree of classes reprentating source code.
   		return $this->parse_source($source, $file);
   	}
   
   	protected function tokens_parse_blocks($token_list){
   
   		static $level = 0;
   
   		if($level == 0)
   			$block = new Php_Parser_Simple_MainBlock();
   		else
   			$block = new Php_Parser_Simple_PhpBlock($level);
   
   		$level++;
   
   		while($token_list->has_next()){
   			$token = $token_list->next();
   			if(is_a($token,'Php_Parser_Simple_TextToken')){
   				switch($token->text()){
   				case '{':
   					$block->add($this->tokens_parse_blocks($token_list));
   					break;
   
   				case '}':
   					$level--;
   					return $block;
   
   				case '(':
   					$block->add($this->tokens_parse_blocks_params($token_list));
   					break;
   				# case ')':
   					# it's done in tokens_parse_blocks_params() method
   					# return $array;
   					# break;
   				default:
   					$block->add($token);
   				}
   			} else{
   				$block->add($token);
   			}
   		}
   
   		$level--;
   		return $block;
   	}
   
   	protected function tokens_parse_blocks_params($token_list){
   
   		$block = new Php_Parser_Simple_ParamBlock();
   
   		while($token_list->has_next()){
   			$token = $token_list->next();
   			if(is_a($token,'Php_Parser_Simple_TextToken')){
   				switch($token->text()){
   				case ')':
   					return $block;
   				}
   			} else{
   				$block->add($token);
   			}
   		}
   		return $block;
   	}
   
   	protected function tokens_parse_class_blocks($block){
   
   		if(!is_a($block, 'Php_Parser_Simple_MainBlock'))
   			return;
   
   		$new_block = new Php_Parser_Simple_MainBlock();
   
   		while($block->has_next()){
   			$token = $tokens[] = $block->next();
   			if($token->text() == 'class'){
   				$class_name_token = $block->next();
   				$class_opts = array();
   				while($block->has_next()){
   					$token = $block->next();
   					if(is_a($token, 'Php_Parser_Simple_PhpBlock'))
   						break;
   					$class_opts[] = $token;
   				}
   				$body = $token;
   				$class = new Php_Parser_Simple_ClassBlock($class_name_token->text(), $class_opts, $body, $class_name_token);
   				$new_block->add($class);
   			} else
   				$new_block->add($token);
   		}	
   
   		return $new_block;
   	}
   
   	/**
   	*  for a given file, parse php tokens and return a flat list of tokens objects (SimpleToken and PhpToken)
   	*
   	*/
   	protected function get_tokens($source, $file=){
   
   		$tokens = token_get_all($source);
   		$token_list = new Php_Parser_Simple_TokenList();
   
   		foreach ($tokens as $token) {
   
   			if (is_string($token)) {
   				// simple 1-character token
   				switch($token){
   					case ';':
   						$token_list->add(new Php_Parser_Simple_TextToken(null, $token, $this->block_level, $this->line, $this->col, $file));
   						# end statement
   						break;
   					case '{':
   						$this->block_level++;
   						$token_list->add(new Php_Parser_Simple_TextToken(null, $token, $this->block_level, $this->line, $this->col, $file));
   						break;
   					case '}':
   						$this->block_level--;
   						$token_list->add(new Php_Parser_Simple_TextToken(null, $token, $this->block_level, $this->line, $this->col, $file));
   						break;
   					case '(':
   					case ')':
   						$token_list->add(new Php_Parser_Simple_TextToken(null, $token, $this->block_level, $this->line, $this->col, $file));
   						break;
   					default:
   						# do nothing.
   						$token_list->add(new Php_Parser_Simple_TextToken(null, $token, $this->block_level, $this->line, $this->col, $file));
   						# echo "# get_tokens() (char) : $token\n";
   				}
   				$this->update_line_and_column_positions($token, $this->line, $this->col);
   			} else {
   				// token array
   				list($id, $text) = $token;
   
   				switch ($id) {
   
   					# ignore some tokens not interesting here.
   					case T_COMMENT:
   					case T_ML_COMMENT:   // we've defined this
   					case T_DOC_COMMENT:  // and this
   						# $token_list->add(new CommentToken($id, $text, $this->block_level, $this->line, $this->col, $file));
   						break;
   					case T_WHITESPACE:
   						# $token_list->add(new SpacingToken($id, $text, $this->block_level, $this->line, $this->col, $file));
   						break;
   					case T_OPEN_TAG:
   					case T_CLOSE_TAG:
   						$token_list->add(new Php_Parser_Simple_TextToken($id, $text, $this->block_level, $this->line, $this->col, $file));
   						break;
   
   					case T_CONSTANT_ENCAPSED_STRING:
   					case T_LNUMBER:
   						$token_list->add(new Php_Parser_Simple_ScalarToken($id, $text, $this->block_level, $this->line, $this->col, $file));
   						break;
   
   					default:
   						$token_list->add(new Php_Parser_Simple_PhpToken($id, $text, $this->block_level, $this->line, $this->col, $file));
   						break;
   				}
   				$this->update_line_and_column_positions($text, $this->line, $this->col);
   			}
   		}
   
   		return $token_list; # list of tokens objects.
   	}
   
   	protected function update_line_and_column_positions($c, &$line, &$col){
   		// update line count
   		$numNewLines = substr_count($c, "\n");
   		if (1 <= $numNewLines) {
   			// have new lines, add them in
   			$line += $numNewLines;
   			$col  =  1;
   		
   			// skip to right past the last new line, as it won't affect the column position
   			$c = substr($c, strrpos($c, "\n") + 1);
   			if ($c === false) {
   				$c = ;
   			}
   		}
   		
   		// update column count
   		$col += strlen($c);
   	}
   }
   
   
   $file = __FILE__;
   $args = $_SERVER['argv'];
   if(count($args) > 1)
   
   $file = $args[1];
   
   # create a new php parser
   $parser = new Php_Parser_Simple();
   
   $start = microtime(true);
   
   	# parse a php-file and return an object that handle php declarations
   	$php_main_block = $parser->parse_file($file);
   	
   		# get declared classes
   		$classes = $php_main_block->get_classes();
   	
   		# and display methods and attributes.
   		foreach($classes as $class){
   			printf("class %s (%d:%s)\n", $class->name(), $class->line(), $class->file());
   	
   			foreach($class->attributes() as $attr)
   				printf("    %s\n", $attr->to_text());
   
   			foreach($class->methods() as $meth)
   				printf("    %s\n", $meth->to_text());
   
   			# should do the same :
   			# echo $class->to_text($full_print=true, $sort=true);
   
   		}
   
   
   
   $end = microtime(true);
   $delay = ($end - $start);
   echo "$delay\n";
   
   ?>
Personal tools
Languages