Patch for callback type support

2 views
Skip to first unread message

Arend

unread,
Jun 30, 2008, 12:21:10 PM6/30/08
to JSON/XML-RPC Client and Server Implementations
Dear owners,

I've tried using your rpc server and it seems a very nice library.

But it did not support the php callback type, which supports calling
methods in a class. See: http://nl.php.net/callback This supports the
notation array($object,"Method"); call_user_func() obviusly supports
this method too.

This is the patch for the current trunk version to support the
callback type for the addMethod() method. It only supports the PHP5
version, I've not bothered hacking in a PHP4 versions

cheers

Arend


Index: RPCServer.class.php
===================================================================
--- RPCServer.class.php (revision 36)
+++ RPCServer.class.php (working copy)
@@ -23,7 +23,6 @@
# }
# $server->addMethod("getTemp");
# //$server->processRequest() is called automatically by the
destructor
-
class RPCServer {
const JSON_RPC_VERSION = "1.1";
const XML_RPC_VERSION = "1.0";
@@ -40,7 +39,7 @@
public $help;
public $address;

- protected $requestID;
+ protected $requestID;
protected $requestType; #XML | JSON | HTTP_GET
protected $responseType; #XML | JSON | JAVASCRIPT
protected $isJSONOmitResponseWrapper;
@@ -270,11 +269,24 @@
function addMethod($privateProcName, $publicMethodName = null){
if($this->isFinished)
die("The server's request has already been processed. You may only
invoke 'addMethod' before the 'processRequest' is executed.");
- if(!$publicMethodName)
- $publicMethodName = $privateProcName;
-
- if(!function_exists($privateProcName))
- trigger_error("\$RPCServerInstance->addMethod() failed because the
function \"$privateProcName\" does not exist.");
+ if(!$publicMethodName)
+ {
+ if (is_array($privateProcName))
+ {
+ $publicMethodName = $privateProcName[1];
+ } else {
+ $publicMethodName = $privateProcName;
+ }
+ }
+
+ // deterimine if the function is a decent call_user_func function.
+ if(!is_callable($privateProcName)) {
+ if (is_array($privateProcName)) {
+ trigger_error("\$RPCServerInstance->addMethod() failed because
the method \"" . $privateProcName[1] . "\" is not callable in class
\"" . get_class($privateProcName[0]) . "\".");
+ } else {
+ trigger_error("\$RPCServerInstance->addMethod() failed because
the method \"" . $privateProcName . "\" does not exist.");
+ }
+ }
if(isset($this->publicToPrivateMap[$publicMethodName]))
trigger_error("\$RPCServerInstance->addMethod() failed because the
method name \"$publicMethodName\" has already been assigned to the
function \"" . $this->publicToPrivateMap[$publicMethodName] . "\".");
$this->publicToPrivateMap[$publicMethodName] = $privateProcName;
@@ -624,7 +636,13 @@
if(class_exists('ReflectionFunction') &&
method_exists('ReflectionParameter', 'isArray')){
foreach(array_keys($this->publicToPrivateMap) as $publicProc){
$functionName = $this->publicToPrivateMap[$publicProc];
- $rf = new ReflectionFunction($functionName);
+ if (is_array($functionName)) {
+ $rf = new ReflectionMethod($callback[0], $callback[1]);
+ }
+ else
+ {
+ $rf = new ReflectionFunction($callback);
+ }
$parametersForPrivateProcs[$functionName] = array();
foreach($rf->getParameters() as $param){ #$i =>
if($param->isPassedByReference())
@@ -647,7 +665,7 @@
}
//$param->isOptional() and $param->allowsNull() are not needed
since PHP will raise errors
// when call_user_func is invoked.
- array_push($parametersForPrivateProcs[$functionName],
$paramDetails);
+ array_push($parametersForPrivateProcs[$publicProc],
$paramDetails);
}
}
unset($functionName);
@@ -657,6 +675,7 @@
unset($paramDetails);
}
#Using the PHP tokenizer before PHP 5.1.0
+ #Won't support OOP callbacks.
else {
$privateToPublicMap = array_flip($this->publicToPrivateMap);
if($this->isUsingIncludedFunctions)
@@ -807,7 +826,7 @@
}
}
}
- }
+ }
unset($tokens);
unset($sourceFiles);
unset($sourceFile);
@@ -821,7 +840,7 @@
#Iterate over all public methods and see if their parameter lists
have been found
# by parsing the tokens of the PHP functions.
foreach($this->publicToPrivateMap as $publicProc => $privateProc){
- if(!isset($parametersForPrivateProcs[$privateProc]))
+ if(!isset($parametersForPrivateProcs[$publicProc]))
trigger_error("Because this version of PHP does not support the
Reflection API, unable to use the public method \"$publicProc\"
because its associated private ".
"procedure is located in an included file; to get around
this, you must explicitly ".
"allow externally defined functions by calling \
$RPCServerInstance->useIncludedFunctions(true); this will decrease
performance. ".

Arend

unread,
Jun 30, 2008, 1:41:09 PM6/30/08
to JSON/XML-RPC Client and Server Implementations


On Jun 30, 6:21 pm, Arend <aren...@gmail.com> wrote:
> Dear owners,
>
> I've tried using your rpc server and it seems a very nice library.
>
> But it did not support the php callback type, which supports calling
> methods in a class. See:http://nl.php.net/callbackThis supports the
> notation array($object,"Method"); call_user_func() obviusly supports
> this method too.
>
> This is the patch for the current trunk version to support the
> callback type for the addMethod() method. It only supports the PHP5
> version, I've not bothered hacking in a PHP4 versions
>
> cheers
>
> Arend

It seems I was a bit premature in sending in this patch. There were
still some bugs present. This patch works for me. It should be noted
that i've only tested it in php5.

This patch works for me.
@@ -624,8 +636,14 @@
if(class_exists('ReflectionFunction') &&
method_exists('ReflectionParameter', 'isArray')){
foreach(array_keys($this->publicToPrivateMap) as $publicProc){
$functionName = $this->publicToPrivateMap[$publicProc];
- $rf = new ReflectionFunction($functionName);
- $parametersForPrivateProcs[$functionName] = array();
+ if (is_array($functionName)) {
+ $rf = new ReflectionMethod($functionName[0], $functionName[1]);
+ }
+ else
+ {
+ $rf = new ReflectionFunction($callback);
+ }
+ $parametersForPrivateProcs[$publicProc] = array();
foreach($rf->getParameters() as $param){ #$i =>
if($param->isPassedByReference())
trigger_error("User functions cannot be defined with parameters
passed by reference. The function \"$functionName\" wants the
parameter \"" . $param->getName() . "\" to be passed by reference.");
@@ -906,7 +925,7 @@
# the procedure being described. If this member is missing or
the Null value then the procedure
# does not expect any parameters.
$proc['params'] = array();
- foreach($parametersForPrivateProcs[$privateName] as $param){
+ foreach($parametersForPrivateProcs[$publicName] as $param){
array_push($proc['params'], array("name" => $param['name'],
"type" => $param['type']));
}

@@ -991,7 +1010,8 @@
#Execute the user-defined requested method
###########################################
else {
#Verify that the supplied method is valid
- if(!isset($this->publicToPrivateMap[$this->publicMethodName]) || !
function_exists($this->publicToPrivateMap[$this->publicMethodName])){
+
+ if(!isset($this->publicToPrivateMap[$this->publicMethodName]) || !
is_callable($this->publicToPrivateMap[$this->publicMethodName])){
$this->isMethodNotFound = true;
trigger_error("The function referred to by the public method
\"" . $this->publicMethodName . "\" does not exist.", E_USER_ERROR);
}
@@ -1042,8 +1062,8 @@
$paramsToPass = array();

#Iterate over the function's defined parameter list
- for($i = 0; $i <
count($parametersForPrivateProcs[$privateProcName]); $i++){
- $param = $parametersForPrivateProcs[$privateProcName][$i];
+ for($i = 0; $i < count($parametersForPrivateProcs[$this-
>publicMethodName]); $i++){
+ $param = $parametersForPrivateProcs[$this->publicMethodName][$i];

#Named request parameter matches
if(isset($requestParams[$param['name']])){

Weston Ruter

unread,
Aug 6, 2008, 9:41:19 PM8/6/08
to Arend, json-x...@googlegroups.com
Would you be able to open a new issue on the issue tracker and upload your patch file there?

Thanks!
Weston
Reply all
Reply to author
Forward
0 new messages