Viewing file: Method.php (13.12 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Class that describes a member function within a PHP class * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Method.php,v 1.18 2006/06/25 15:17:45 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */
/** * includes */ require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Function.php"; require_once "CodeGen/PECL/Element/Class.php";
/** * Class that describes a member function within a PHP class * * @category Tools and Utilities * @package CodeGen * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: @package_version@ * @link http://pear.php.net/package/CodeGen */ class CodeGen_PECL_Element_Method extends CodeGen_PECL_Element_Function { function __construct(Codegen_PECL_Element_ObjectInterface $class) { $this->class = $class; $this->classname = $class->getName(); }
/** * The class this method belongs to * * @var object */ protected $class;
/** * Name of class this method belongs to * * @var string */ protected $classname;
/** * Name for procedural alias of this method * * @var string */ protected $proceduralName = "";
function getProceduralName() { return $this->proceduralName; } function setProceduralName($name) { if ($name == "default") { $name = $this->classname."_".$this->name; } else if (!$this->isName($name)) { return PEAR::raiseError("'$name' is not a valid function alias name"); }
$this->proceduralName = $name;
return true; }
/** * distinguishable name getter * * @return string */ function getFullName() { return $this->classname."__".$this->name; }
/** * Is this an abstract method? * * @var bool */ protected $isAbstract = false;
function isAbstract() { $this->isAbstract = true;
return $this->validate(); }
/** * Is this an interface method? * * @var bool */ protected $isInterface = false;
function isInterface() { $this->isInterface = true; $this->isAbstract = true;
return $this->validate(); }
/** * Is this a final method? * * @var bool */ protected $isFinal = false;
function isFinal() { $this->isFinal = true;
return $this->validate(); }
/** * Is this a static method? * * @var bool */ protected $isStatic = false;
function isStatic() { $this->isStatic = true;
return $this->validate(); }
/** * Visibility of this property * * @var string */ protected $access = "public";
function setAccess($access) { switch ($this->access) { case "private": case "protected": case "public": $this->access = $access; return $this->validate(); default: return PEAR::raiseError("'$access' is not a valid access property"); } }
/** * Hook for parameter parsing API function * * @param string C expr. for number of arguments * @param string Argument string * @param array Argument variable pointers */ protected function parseParameterHook($argc, $argString, $argPointers) { if ($this->name == "__construct") { $code = parent::parseParameterHook($argc, $argString, $argPointers); $code.= "\n _this_zval = getThis();\n"; } else { $code = " if (zend_parse_method_parameters($argc TSRMLS_CC, getThis(), \"$argString\", ".join(", ",$argPointers).") == FAILURE) { return; }
"; } $code .= " _this_ce = Z_OBJCE_P(_this_zval);\n\n";
$payload = $this->class->getPayloadType(); if ($payload) { $code.= " payload = (php_obj_{$this->classname} *) zend_object_store_get_object(_this_zval TSRMLS_CC);\n"; }
return $code; }
/** * Generate local variable declarations * * @return string C code snippet */ function localVariables($extension) { $code = parent::localVariables($extension); $code.= " zend_class_entry * _this_ce;\n"; if ($this->name == "__construct") { $code.= " zval * _this_zval;\n"; }
$payload = $this->class->getPayloadType(); if ($payload) { $code.= " php_obj_{$this->classname} *payload;\n"; }
return $code; }
/** * Set parameter and return value information from PHP style prototype * * @access public * @param string PHP style prototype * @return bool Success status */ function setProto($proto, $extension) { $err = parent::setProto($proto, $extension); if (PEAR::isError($err)) { return $err; } if ($this->name != "__construct") { $param = array(); $param['name'] = "_this_zval"; $param['type'] = "object"; $param['subtype'] = $this->classname; $param['byRef'] = true;
array_unshift($this->params, $param); } }
/** * Create registration line for method table * * @param string Name of class owning this method * @return string C code snippet */ function methodEntry() { $code = "";
// TODO catch arg #2->type == void $arginfo = (count($this->params)>1) ? ($this->getFullName()."_args") : "NULL";
if ($this->isAbstract || $this->isInterface) { $code.= "ZEND_FENTRY({$this->name}, NULL, $arginfo, ZEND_ACC_ABSTRACT | "; if ($this->isInterface) { $code.= " ZEND_ACC_INTERFACE | "; } } else { $code.= "PHP_ME({$this->classname}, {$this->name}, $arginfo, /**/"; }
$code.= "ZEND_ACC_".strtoupper($this->access);
if ($this->isStatic) { $code.= " | ZEND_ACC_STATIC"; }
if ($this->isFinal) { $code.= " | ZEND_ACC_FINAL"; }
$code.= ")"; return $code; }
/** * Create registration line for method table * * @param string Name of class owning this method * @return string C code snippet */ function functionAliasEntry() { if (!$this->proceduralName) { return ""; }
// TODO arg_info? return " PHP_MALIAS({$this->classname}, {$this->proceduralName}, {$this->name}, NULL, ZEND_ACC_PUBLIC)\n"; } /** * Create proto line for method * * @param string Name of class owning this method * @return string C code snippet */ function cProto() { if ($this->isAbstract || $this->isInterface) { return ""; } return "PHP_METHOD({$this->classname}, {$this->name})"; }
/** * Create C code implementing the PHP userlevel function * * @access public * @param class Extension extension the function is part of * @return string C code implementing the function */ function cCode($extension) { if (!$this->isAbstract && !$this->isInterface) { return parent::cCode($extension); }
return ""; }
/** * Validate settings, spot conflicts * * @return true or exception */ function validate() { /* an abstract method can't be final or private and can't have code */ if ($this->isAbstract && $this->isFinal) { return PEAR::raiseError("A method can't be abstract and final at the same time"); }
if ($this->isAbstract && $this->access == "private") { return PEAR::raiseError("A method can't be abstract and private at the same time"); }
if ($this->isAbstract && !empty($this->code)) { return PEAR::raiseError("A method can't be abstract and implemented at the same time"); }
// TODO add "abstract may not have test" as soon as test mess is cleaned up return true; }
/** * The role attribute doesn't apply here * * @param string * @return exception */ function setRole($role) { return PEAR::raiseError("the role attribute is not defined for class member functions"); }
/** * Code addition must be validated here * * @param string code snippet */ function setCode($code) { parent::setCode($code);
return $this->validate(); }
/** * Method name checking is less strict * * Method names can't clash with PHP standard functions * so we can just check for syntax and keywords here * * @param string method name */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid function name"); } if (self::isKeyword($name)) { return PEAR::raiseError("'$name' is a reserved word which is not valid for function names"); } $this->name = $name; return true; }
/** * Create test case for this function * * @access public * @param object extension the function is part of * @return object generated test case */ function createTest(CodeGen_PECL_Extension $extension) { if ($this->isAbstract || $this->isInterface) { return null; }
$test = parent::createTest($extension);
$test->setName($this->getFullName()); $test->setTitle($this->classname."::".$this->name."() member function"); return $test; }
/** * Code needed ahead of the method table * * Abstract/Interface methods need to define their argument * list ahead of the method table * * @returns string */ function argInfoCode() { $code = "";
if (count($this->params) > 0) { $code.= "ZEND_BEGIN_ARG_INFO(".$this->getFullName()."_args, 0)\n";
$params = $this->params; array_shift($params);
$useTypeHints = true;
foreach($params as $param) { if ($param['type'] != "object" || !isset($param['subtype'])) { $useTypeHints = false; break; } }
// TODO optional paramteres? foreach($params as $param) { $byRef = empty($param["byRef"]) ? 0 : 1; if ($useTypeHints) { $code.= " ZEND_ARG_OBJ_INFO(0, $param[name], $param[subtype], 0)\n"; } else { $code.= " ZEND_ARG_INFO($byRef, $param[name])\n"; } } $code.= "ZEND_END_ARG_INFO()\n"; }
return $code; }
}
?>
|