Viewing file: Function.php (47.65 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Class describing a function within a PECL extension * * 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: Function.php,v 1.32 2006/08/14 22:50:43 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen */
/** * includes */ require_once "CodeGen/PECL/Element.php";
require_once "CodeGen/Tools/Tokenizer.php";
/** * Class describing a function within a PECL extension * * @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_Function extends CodeGen_PECL_Element { /** * The function name * * @access private * @var string */ protected $name = "";
/** * name setter * * @param string */ function setName($name) { if (!self::isName($name)) { return PEAR::raiseError("'$name' is not a valid function name"); } switch ($this->role) { case "internal": if (!$this->isInternalName($name)) { return PEAR::raiseError("'$name' is not a valid internal function name"); } break;
case "public": // keywords are not allowed as function names if (self::isKeyword($name)) { return PEAR::raiseError("'$name' is a reserved word which is not valid for function names"); } // you should not redefine standard PHP functions foreach(get_extension_funcs("standard") as $stdfunc) { if (!strcasecmp($name, $stdfunc)) { return PEAR::raiseError("'$name' is already the name of a PHP standard function"); } } break; }
$this->name = $name; return true; }
/** * name getter * * @return string */ function getName() { return $this->name; }
/** * distinguishable name getter * * here it's just the same as the plain name * but e.g. for class methods that wouldn't * be enough * * @return string */ function getFullName() { return $this->name; }
/** * A short description * * @access private * @var string */ protected $summary = "";
/** * summary getter * * @param string */ function setSummary($text) { $this->summary = $text; return true; }
/** * A long description * * @access private * @var string */ protected $description = "";
/** * description setter * * @param string */ function setDescription($text) { $this->description = $text; return true; }
/** * Type of function: internal, public * * @access private * @var string */ protected $role = "public";
/** * role setter * * @param string */ function setRole($role) { switch($role) { case "internal": if (!$this->isInternalName($this->name)) { return PEAR::raiseError("'{$this->name}' is not a valid internal function name"); } break;
case "public": break;
case "private": return PEAR::raiseError("'private' functions are no longer supported, use global <code> sections instead"); break;
default: return PEAR::raiseError("'$role' is not a valid function role"); } $this->role = $role; return true; }
function getRole() { return $this->role; }
/** * Function has variable arguments "..." * * @access private * @var bool */ protected $varargs = false;
/** * Function prototype * * @access private * @var string */ protected $proto = "void unknown(void)";
/** * Function returntype (parsed from proto) * * @access private * @var string */ protected $returns = "void";
/** * Function parameters (parsed from proto) * * @access private * @var array */ protected $params = array();
/** * Number of optional parameters (parsed from proto) * * @access private * @var int */ protected $optional = 0;
/** * Does this function have by-reference parameters? * * @var bool */ protected $hasRefArgs = false;
/** * 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) { $this->proto = $proto;
if ($extension->haveVersion("0.9.0rc1")) { $stat = $this->newSetProto($proto, $extension); } else { $stat = $this->oldSetProto($proto); }
return $stat; }
/** * Set parameter and return value information from PHP style prototype * * @param string PHP style prototype * @return bool Success status */ private function newSetProto($proto, $extension) { $tokenGroups = array(); $optionals = 0; $firstOptional = 0; $squareBrackets = 0; $scanner = new CodeGen_Tools_Tokenizer($proto);
// group #0 -> return type and function name $group = array(); while ($scanner->nextToken()) { if ($scanner->type === 'char' && $scanner->token === '(') { break; } $group[] = array($scanner->type, $scanner->token); } $tokenGroups[] = $group; // all following groups are parameters delimited by ',' $group = array(); while ($scanner->nextToken()) { if ($scanner->type === 'char') { if ($scanner->token === '[') { $squareBrackets++; if(!$firstOptional) { if (count($group)) { $tokenGroups[] = $group; $group = array(); } $firstOptional = count($tokenGroups); } continue; } if ($scanner->token === ',') { if (count($group)) { $tokenGroups[] = $group; $group = array(); } continue; }
if ($scanner->token === ']') { $squareBrackets--; continue; }
if ($scanner->token === ')') { $tokenGroups[] = $group; $group = array(); break; } }
$group[] = array($scanner->type, $scanner->token); }
if ($squareBrackets > 0) { return PEAR::raiseError("missing closing ']'"); } if ($squareBrackets < 0) { return PEAR::raiseError("to many closing ']'"); }
// // get return type and function name // $tokens = array_shift($tokenGroups); // first the function name list($type, $token) = array_pop($tokens); if ($type !== 'char' || $token !== '@') { // @ is allowed as function name placeholder if ($type !== 'name' || !self::isName($token)) { return PEAR::raiseError("'$token' is not a valid function name"); } if (self::isKeyword($token)) { return PEAR::raiseError("keyword '$token' can't be used as function name"); } }
$functionName = $token; // function name is not really used, taken from <function> tag instead // TODO: add WARNING for mismatch? if (! empty($this->name)) { $functionName = $this->name; } else { $this->name = $functionName; } // then the return type list($type, $token) = array_shift($tokens); if ($type !== 'name' || !self::isType($token)) { return PEAR::raiseError("'$token' is not a valid return type"); } $returnType = $token; // some types may carry a name if ($token === "object" || $token == "resource") { if (isset($tokens[0][0]) && $tokens[0][0] === 'name') { list($type, $token) = array_shift($tokens); $returnSubtype = $token; } } // return by reference? if (count($tokens) && $tokens[0][0] === 'char' && $tokens[0][1] === '&') { list($type, $token) = array_shift($tokens); $returnByRef = true; } // any tokens left? if (count($tokens)) { return PEAR::raiseError("extra token '".$tokens[0][1]."' in function prototype"); } // // now the parameters one by one // $params = array(); $vararg = false; while ($tokens = array_shift($tokenGroups)) { if ($vararg) { return PEAR::raiseError("no further parameters are allowed after '...'"); } $param = array(); // check for default value assignment $equals = false; $default = array(); foreach ($tokens as $key => $value) { if ($value[0] === 'char' && $value[1] === '=') { $equals = $key; break; } } if ($equals !== false) { while (count($tokens) > $equals + 1) { array_unshift($default, array_pop($tokens)); } array_pop($tokens); } // get parameter name list($type, $token) = array_pop($tokens); if ($type !== 'name') { return PEAR::raiseError("'$token' is not a valid parameter name (1)"); } $param['name'] = $token; // then the parameter type list($type, $token) = array_shift($tokens); if ($type !== 'name' || !self::isType($token)) { switch ($param["name"]) { case "void": if (!empty($params)) { return PEAR::raiseError("only the first (and only) paramter can be of type void"); } $param["type"] = $param["name"]; $param["name"] = ""; break; case "...": if ($optionals) { // TODO not set yet ??? return PEAR::raiseError("'...' varargs can't be combined with optional args"); } $vararg = true; $param["type"] = $param["name"]; $param["name"] = ""; break; default: return PEAR::raiseError("'$token' is not a valid type for parameter '".$param['name']."'"); } } else { $param['type'] = $token; } if (!empty($param["name"]) && !self::isName($param["name"])) { return PEAR::raiseError("'{$param[name]}' is not a valid parameter name (2)"); }
// some types may carry a name if ($token === "object" || $token === "resource") { if ($tokens[0][0] === 'name') { list($type, $token) = array_shift($tokens); $param['subtype'] = $token; } } // pass by reference? if (count($tokens) && $tokens[0][0] === 'char' && $tokens[0][1] === '&') { list($type, $token) = array_shift($tokens); if ($type != "array" && $type != "mixed") { return PEAR::raiseError("only 'array' and 'mixed' arguments may be passed by reference, '$param[name]' is of type '$type'"); } $param['byRef'] = true; $this->hasRefArgs = true; } // any tokens left? if (count($tokens)) { return PEAR::raiseError("extra token '".$tokens[0][1]."' in specification of parameter '$param[name]'"); } // do we have a default value? switch (count($default)) { case 0: break; case 1: list($type, $token) = array_shift($default); switch ($type) { case 'string': case 'char': $param['default'] = '"'.str_replace('"', '\"', $token).'"'; break; case 'numeric': $param['default'] = $token; break; case 'name': switch (strtolower($token)) { // first check for 'known' PHP constants case 'true': case 'false': case 'null': case 'array()': $param['default'] = $token; break; default: // now see if this is a constand defined by this extension $constants = $extension->getConstants(); if (isset($constants[$token])) { $param["default"] = $constants[$token]->getValue(); } else { return PEAR::raiseError("invalid default value '$token' specification for parameter '$param[name]' ($type)"); } } break; default: return PEAR::raiseError("invalid default value '$token' specification for parameter '$param[name]' ($type)"); } break; default: return PEAR::raiseError("invalid default value '$token' specification for parameter '$param[name]' ($type)"); } if ($firstOptional && count($params)+1 >= $firstOptional) { $param['optional'] = true; $optionals++; } $params[] = $param; }
$this->returns = $returnType;
if (isset($returnSubtype)) { $this->returns .= " $returnSubtype"; }
if (isset($returnByRef)) { $this->returns .= " &"; }
$this->params = $params; $this->optional = $optionals; $this->vararg = $vararg;
return true; }
function oldSetProto($proto) { // This is the classic setProto() version, we keep it for now // as the new version is not 100% backwards compatible yet // 'tokenize' it $tokens = array();
// we collect valid C names as Strings, any other character for itself, blanks are skipped // TODO: this does no longer work if we ever add default values ... $len = strlen($proto); $name = ""; for ($n = 0; $n < $len; $n++) { $char = $proto{$n}; if (ctype_alpha($char) || $char == '_' || ($n && ctype_digit($char))) { $name .= $char; } else if ($char == '.' && $proto{$n+1} == '.' && $proto{$n+2} == '.') { $name = "..."; $n += 2; } else { if ($name) $tokens[] = $name; $name = ""; if (trim($char)) { $tokens[] = $char; } } }
if ($name) { $tokens[] = $name; }
$n = 0; $opts = 0; $numopts = 0;
$params = array();
$returnType = ($this->isType($tokens[$n])) ? $tokens[$n++] : "void";
$functionName = $tokens[$n++];
if ($returnType === "resource" && $tokens[$n] !== "(") { $returnSubtype = $functionName; $functionName = $tokens[$n++]; }
// function name is not really used, taken from <function> tag instead // TODO: add WARNING for mismatch? if (! empty($this->name)) { $functionName = $this->name; } else { $this->name = $functionName; }
if ($tokens[$n++] != '(') return PEAR::raiseError("'(' expected instead of '$tokens[$n]'"); if ($tokens[$n] == ')') { /* done */ } else if ($tokens[$n] == '...') { $params[0]['type'] = "..."; $n++; } else { for ($param = 0; $tokens[$n]; $n++, $param++) { if ($tokens[$n] == '[') { $params[$param]['optional'] = true; $opts++; $n++; if ($param > 0) { if ($tokens[$n] != ',') { return PEAR::raiseError("',' expected after '[' instead of '$token[$n]'"); } $n++; } }
if (!$this->isType($tokens[$n])) { return PEAR::raiseError("type name expected instead of '$tokens[$n]'"); }
$params[$param]['type'] = $tokens[$n]; $n++;
if ($tokens[$n] == "&") { $params[$param]['byRef'] = true; $n++; }
if ($this->isName($tokens[$n])) { $params[$param]['name']=$tokens[$n]; $n++; }
if ($tokens[$n] == "&") { $params[$param]['byRef'] = true; $n++; }
if ($params[$param]['type'] === "resource" && $this->isName($tokens[$n])) { $params[$param]['subtype'] = $params[$param]['name']; $params[$param]['name'] = $tokens[$n]; $n++; }
if ($tokens[$n] == '[') { $n--; continue; }
if ($tokens[$n] == ',') continue; if ($tokens[$n] == ']') break; if ($tokens[$n] == ')') break;
}
$numopts = $opts; while ($tokens[$n] == ']') { $n++; $opts--; } if ($opts != 0) { return PEAR::raiseError("'[' / ']' count mismatch"); } }
if ($tokens[$n] != ')') { return PEAR::raiseError("')' expected instead of '$tokens[$n]'"); }
$this->returns = $returnType;
if (isset($returnSubtype)) { $this->returns .= " $returnSubtype"; }
$this->params = $params; $this->optional = $numopts;
return true; }
/** * Code snippet * * @access private * @var string */ protected $code = "";
/** * Source file of code snippet * * @access private * @var string */ protected $codeFile = "";
/** * Source line of code snippet * * @access private * @var int */ protected $codeLine = 0;
/** * Code setter * * @param string code snippet * @param int source line * @param int source filename */ function setCode($code, $line = 0, $file = "") { $this->code = $code; $this->codeFile = $file; $this->codeLine = $line; return true; }
/** * Code getter * * @return string */ function getCode() { return $this->code; }
/** * test code snippet * * @var string */ protected $testCode = "echo 'OK'; // no test case for this function yet";
/** * testCode setter * * @param string code snippet */ function setTestCode($code) { $this->testCode = $code; }
/** * testCode getter * * @return string */ function getTestCode() { return $this->testCode; }
/** * expected test result string * * @var array */ protected $testResult = array(); /** * testResult setter * * @param string result text * @param string test output comparison mode */ function setTestResult($text, $mode = "plain") { $this->testResult = array("result" => $text, "mode" => $mode); }
/** * testResult getter * * @return array */ function getTestResult() { return $this->testResult; }
/** * test code description * * @var string */ protected $testDescription = "";
/** * testDescritpion setter * * @param string text */ function setTestDescription($text) { $this->testDescription = $text; }
/** * testDescription getter * * @return string */ function getTestDescription() { return $this->testDescription; }
/** * test additional skipif condition * * @var string */ protected $testSkipIf = "";
/** * testSkipIf setter * * @param string code snippet */ function setTestSkipIf($code) { $this->testSkipIf = $code; }
/** * testSkipIf getter * * @return string */ function getTestSkipIf() { return $this->testSkipIf; }
/** * test additional ini condition * * @var string */ protected $testIni = "";
/** * testIni setter * * @param string code snippet */ function setTestIni($code) { $this->testIni = $code; }
/** * testIni getter * * @return string */ function getTestIni() { return $this->testIni; }
/** * Check whether a function name is already used internally * * @access public * @param string function name * @return bool true if function name is already used internally */ function isInternalName($name) { switch ($name) { case "MINIT": case "MSHUTDOWN": case "RINIT": case "RSHUTDOWN": case "MINFO": return true; }
return false; }
/** * Helper for cCode * * @param string Parameter spec. array * @param string default value for type * @return string default value */ function defaultval($param, $default) { if (isset($param["default"])) { return $param["default"]; }
return $default; }
/** * 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) { return " if (zend_parse_parameters($argc TSRMLS_CC, \"$argString\", ".join(", ",$argPointers).") == FAILURE) { return; } "; }
/** * Generate local variable declarations * * @return string C code snippet */ function localVariables($extension) { $code = "";
$returns = explode(" ", $this->returns);
// for functions returning a named resource we create payload pointer variable $resources = $extension->getResources(); if ($returns[0] === "resource") { if (isset($returns[1]) && isset($resources[$returns[1]])) { $resource = $resources[$returns[1]]; $payload = $resource->getPayload(); if ($resource->getAlloc()) { $code .= " $payload * return_res = ($payload *)ecalloc(1, sizeof($payload));\n"; } else { $code .= " $payload * return_res;\n"; } } else { $code .= " void * return_res;\n"; } $code .= " long return_res_id = -1;\n"; }
return $code; }
/** * 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) { $code = "\n";
$returns = explode(" ", $this->returns);
switch ($this->role) { case "public": if ($this->ifCondition) { $code .= "#if {$this->ifCondition}\n"; }
// function prototype comment $code .= "/* {{{ proto {$this->proto}\n "; if (!empty($this->summary)) { $code .= $this->summary; } $code .= " */\n";
// function declaration $code .= $this->cProto()."\n"; $code .= "{\n"; $code .= $this->localVariables($extension);
// now we create local variables for all parameters // at the same time we put together the parameter parsing string if (is_array($this->params) && count($this->params)) { $argString = ""; $argPointers = array(); $optional = false; $postProcess = ""; $zvalType = false; foreach ($this->params as $param) { if ($param["type"] === "void" || $param["type"] === "...") { continue; }
$name = $param['name']; if ($param['type'] == "resource" && $extension->haveVersion("1.0.0alpha")) { $argPointers[] = "&{$name}_res"; } else { $argPointers[] = "&$name"; }
if (isset($param['optional']) && !$optional) { $optional = true; $argString .= "|"; }
switch ($param['type']) { case "bool": $argString .= "b"; $default = $this->defaultval($param, "0"); $code .= " zend_bool $name = $default;\n"; break;
case "int": $argString .= "l"; $default = $this->defaultval($param, "0"); $code .= " long $name = $default;\n"; break;
case "float": $argString .= "d"; $default = $this->defaultval($param, "0.0"); $code .= " double $name = $default;\n"; break;
case "string": $argString .= "s"; $default = $this->defaultval($param, "NULL"); $code .= " const char * $name = $default;\n"; $code .= sprintf(" int {$name}_len = %d;\n", $default==="NULL" ? 0 : strlen($default) - 2); $argPointers[] = "&{$name}_len"; break;
case "unicode": $argString .= "u"; $default = $this->defaultval($param, "NULL"); $code .= " const char * $name = $default;\n"; $code .= sprintf(" int {$name}_len = %d;\n", $default==="NULL" ? 0 : strlen($default) - 2); $argPointers[] = "&{$name}_len"; break;
case "text": $argString .= "t"; $default = $this->defaultval($param, "NULL"); $code .= " const char * $name = $default;\n"; $code .= sprintf(" int {$name}_len = %d;\n", $default==="NULL" ? 0 : strlen($default) - 2); $code .= " int {$name}_type = IS_STRING;\n"; // TODO depends on input encoding $argPointers[] = "&{$name}_len"; break;
case "array": $zvalType = true; $argString .= "a"; $code .= " zval * $name = NULL;\n"; $code .= " HashTable * {$name}_hash = NULL;\n"; $postProcess.= " {$name}_hash = HASH_OF($name);\n"; break;
case "object": $zvalType = true; $code .= " zval * $name = NULL;\n"; if (isset($param['subtype'])) { $argString .= "O"; $argPointers[] = "$param[subtype]_ce_ptr"; } else { $argString .= "o"; } break;
case "resource": $zvalType = true; $argString .= "r";
if ($extension->haveVersion("1.0.0alpha")) { $resVar = $name."_res"; $payloadVar = $name; $idVar = $name."_resid"; } else { $resVar = $name; $payloadVar = "res_".$name; $idVar = $name."_id"; }
$code .= " zval * $resVar = NULL;\n"; $code .= " int $idVar = -1;\n";
$resources = $extension->getResources(); if (isset($param['subtype']) && isset($resources[$param['subtype']])) { $resource = $resources[$param['subtype']]; if ($extension->haveVersion("1.0.0dev")) { $varname = $name; } else { $varname = "res_{$name}"; } $code .= " ".$resource->getPayload()." * $payloadVar;\n"; $postProcess .= " ZEND_FETCH_RESOURCE($payloadVar, ".$resource->getPayload()." *, &$resVar, $idVar, \"$param[subtype]\", le_$param[subtype]);\n"; } else { $postProcess .=" ZEND_FETCH_RESOURCE(???, ???, $resVar, $idVar, \"???\", ???_rsrc_id);\n"; } break;
case "stream": $zvalType = true; $argString .= "r"; $code .= " zval * {$name}_zval = NULL;\n"; $code .= " php_stream * $name = NULL:\n"; $postProcess.= " php_stream_from_zval($name, &_z$name);\n"; break;
case "callback": $postProcess.= " if (!zend_is_callable({$name}, 0, NULL)) {\n"; $postProcess.= " php_error(E_WARNING, \"Invalid comparison function.\");\n"; $postProcess.= " return;"; $postProcess.= " }\n"; /* fallthru */ case "mixed": $zvalType = true; $argString .= "z"; $code .= " zval * {$name} = NULL;\n"; break; }
if (empty($param['byRef']) && ($param['type'] == 'mixed' || $param['type'] == 'array')) { $argString .= "/"; } else if (!$zvalType) { // TODO: pass by ref for 'simple' types requires further thinking } } }
// now we do the actual parameter parsing if (empty($argString)) { if (!empty($this->params) && $this->params[0]['type'] == "...") { $code .= "/* custom parsing code required */\n\n"; } else { $code .= " if (ZEND_NUM_ARGS()>0) {\n WRONG_PARAM_COUNT;\n }\n\n"; } } else { if ($this->varargs) { $argc = sprint("MIN(ZEND_NUM_ARGS(),%d)", count($this->params)-1); } else { $argc = "ZEND_NUM_ARGS()"; }
$code .= $this->parseParameterHook($argc, $argString, $argPointers); if ($this->varargs) { // TODO can't do a zend_get_parameters_array with offset yet }
if ($postProcess) { $code.= "$postProcess\n\n"; } } // for functions returning an array we initialize return_value if ($returns[0] === "array") { $code.=" array_init(return_value);\n\n"; }
if ($this->code) { if ($extension->getLinespecs()) { // generate #line preprocessor directive if ($this->codeLine) { $linedef = "#line {$this->codeLine} "; if ($this->codeFile) { $linedef.= '"'.$this->codeFile.'"'; } } else { $linedef = ""; } }
// if function code is specified so we add it here if (isset($linedef)) { $code .= "$linedef\n"; } $code .= $extension->codegen->varblock($this->code);
// when a function returns a named resource we know what to do if ($returns[0] == "resource" && isset($returns[1])) { $code .= " return_res_id = ZEND_REGISTER_RESOURCE(return_value, return_res, le_$returns[1]);\n"; } } else { // no code snippet was given so we produce a suggestion for the return statement $code .= " php_error(E_WARNING, \"{$this->name}: not yet implemented\"); RETURN_FALSE;\n\n"; switch ($returns[0]) { case "void": break; case "bool": $code .= " RETURN_FALSE;\n"; break; case "int": $code .= " RETURN_LONG(0);\n"; break; case "float": $code .= " RETURN_DOUBLE(0.0);\n"; break; case "string": $code .= " RETURN_STRINGL(\"\", 0, 1);\n"; break;
case "array": $code .= " array_init(return_value);\n"; break; case "object": $code .= " object_init(return_value)\n"; break; case "resource": if (isset($returns[1])) { $code .= " ZEND_REGISTER_RESOURCE(return_value, return_res, le_$returns[1]);\n"; } else { $code .= " /* RETURN_RESOURCE(...); */\n"; } break; case "stream": $code .= " /* php_stream_to_zval(stream, return_value); */\n"; break; case "mixed": $code .= " /* RETURN_...(...); */\n"; break; default: $code .= " /* UNKNOWN RETURN TYPE '$this->returns' */\n"; break; } } $code .= "}\n/* }}} {$this->name} */\n\n";
if ($this->ifCondition) { $code .= "#endif\n"; }
break; case "internal": if (!empty($this->code)) { $code .= $extension->codegen->varblock($this->code."\n"); } break; } return $code; }
/** * Create DocBook reference entry for the function * * @access public * @param string base (currently not used) * @return string DocBook XML code */ function docEntry($base) { $xml = '<?xml version="1.0" encoding="iso-8859-1"?> <!-- '.'$'.'Revision: 1.0 $ --> <refentry id="function.' . strtolower(str_replace("_", "-", $this->name)) . '"> <refnamediv> <refname>' . $this->name . '</refname> <refpurpose>' . $this->summary . '</refpurpose> </refnamediv> <refsect1> <title>Description</title> <methodsynopsis> '; $xml .= " <type>{$this->returns}</type><methodname>{$this->name}</methodname>\n"; if (empty($this->params) || $this->params[0]["type"] === "void") { $xml .= " <void/>\n"; } else if ($this->params[0]["type"] === "...") { $xml .= " <methodparam choice='opt' rep='repeat'><type>mixed</type><parameter>...</parameter></methodparam>\n"; } else { foreach ($this->params as $key => $param) { if (isset($param['optional'])) { $xml .= " <methodparam choice='opt'>"; } else { $xml .= " <methodparam>"; } $xml .= "<type>$param[type]</type><parameter>"; if (isset($param['byRef'])) { $xml .= "&"; } $xml .= "$param[name]</parameter>"; $xml .= "</methodparam>\n"; } }
$description = $this->description;
if (!strstr($this->description,"<para>")) { $description = " <para>\n$description </para>\n"; }
$xml .= ' </methodsynopsis> '.$description.' </refsect1> </refentry> '; return $xml; }
/** * write test case for this function * * @access public * @param class Extension extension the function is part of */ function writeTest(CodeGen_PECL_Extension $extension) { $test = $this->createTest($extension);
if ($test instanceof CodeGen_PECL_Element_Test) { $test->writeTest($extension); } }
/** * 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->testCode) { return false; }
$test = new CodeGen_PECL_Element_Test; $test->setName($this->name); $test->setTitle($this->name."() function"); if ($this->testDescription) { $test->setDescription($this->testDescription); } if ($this->testIni) { $test->addIni($this->testIni); } $test->setSkipIf("!extension_loaded('".$extension->getName()."')"); if ($this->testSkipIf) { $test->addSkipIf($this->testSkipIf); } $test->setCode($this->testCode); if (!empty($this->testResult)) { $test->setOutput($this->testResult['result']); if (isset($this->testResult['mode'])) { $test->setMode($this->testResult['mode']); } } return $test; }
/** * C function signature * * @return string C snippet */ function cProto() { return "PHP_FUNCTION({$this->name})"; }
/** * Create C header entry for userlevel function * * @access public * @param class Extension extension the function is part of * @return string C header code snippet */ function hCode($extension) { $code = "";
if ($this->ifCondition) { $code .= "#if {$this->ifCondition}\n"; }
$code .= $this->cProto(); if ($code) { $code.= ";\n"; }
$code.= $this->argInfoCode();
if ($this->ifCondition) { $code .= "#endif\n"; }
return $code; }
/** * Code needed ahead of the function table * * Only required for functions that accept parameters by reference * * @returns string */ function argInfoCode() { $code = "";
// generate refargs mask if needed if ($this->hasRefArgs) { $code.= "ZEND_BEGIN_ARG_INFO({$this->name}_arg_info, 0)\n"; foreach ($this->params as $param) { $code.= " ZEND_ARG_PASS_INFO(". (isset($param["byRef"]) ? 1 : 0) .")\n"; } $code.= "ZEND_END_ARG_INFO()\n"; }
return $code; }
/** * Generate registration entry for extension function table * * @return string */ function functionEntry() { $code = "";
$arginfo = $this->hasRefArgs ? "{$this->name}_arg_info" : "NULL";
if ($this->ifCondition) { $code .= "#if {$this->ifCondition}\n"; }
$code .= sprintf(" PHP_FE(%-20s, %s)\n", $this->name, $arginfo);
if ($this->ifCondition) { $code .= "#endif\n"; }
return $code; } }
?>
|