Current File : //opt/RZphp72/includes/CodeGen/PECL/Element/Method.php |
<?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-2008 Hartmut Holzgraefe
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Method.php,v 1.23 2006/10/17 11:08:04 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-2008 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 Argument string
* @param array Argument variable pointers
* @param int Return value for number of arguments
*/
protected function parseParameterHook($argString, $argPointers, &$count)
{
$count = count($this->params) - 1;
if ($this->varargs) {
$argc = sprintf("MIN(ZEND_NUM_ARGS(), %d)", $count);
} else {
$argc = "ZEND_NUM_ARGS()";
}
if ($this->name == "__construct") {
$code = parent::parseParameterHook($argString, $argPointers, $count);
$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);
switch ($this->name) {
case "__construct": $code.=" | ZEND_ACC_CTOR"; break;
case "__desctruct": $code.=" | ZEND_ACC_DTOR"; break;
case "__clone": $code.=" | ZEND_ACC_CLONE"; break;
default: break;
}
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
*
* @param array
* @returns string
*/
function argInfoCode($params)
{
array_shift($params);
return parent::argInfoCode($params);
}
/**
* Name for ARG_INFO definition
*
* @return string
*/
function argInfoName()
{
return $this->getFullName()."_args";
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode:nil
* End:
*/
?>