One more attempt at fixing unit tests
[plcapi.git] / src / Wrapper.php
index 02ced67..a45100b 100644 (file)
@@ -8,8 +8,7 @@
 namespace PhpXmlRpc;
 
 /**
- * PHP-XMLRPC "wrapper" class.
- * Generate stubs to transparently access xmlrpc methods as php functions and vice-versa.
+ * PHP-XMLRPC "wrapper" class - generate stubs to transparently access xmlrpc methods as php functions and vice-versa.
  * Note: this class implements the PROXY pattern, but it is not named so to avoid confusion with http proxies.
  *
  * @todo use some better templating system for code generation?
@@ -18,7 +17,7 @@ namespace PhpXmlRpc;
  */
 class Wrapper
 {
-    /// used to hold a reference to object instances whose methods get wrapped by wrap_php_function(), in 'create source' mode
+    /// used to hold a reference to object instances whose methods get wrapped by wrapPhpFunction(), in 'create source' mode
     public static $objHolder = array();
 
     /**
@@ -34,7 +33,7 @@ class Wrapper
      *
      * @return string
      */
-    public function php_2_xmlrpc_type($phpType)
+    public function php2XmlrpcType($phpType)
     {
         switch (strtolower($phpType)) {
             case 'string':
@@ -42,6 +41,7 @@ class Wrapper
             case 'integer':
             case Value::$xmlrpcInt: // 'int'
             case Value::$xmlrpcI4:
+            case Value::$xmlrpcI8:
                 return Value::$xmlrpcInt;
             case Value::$xmlrpcDouble: // 'double'
                 return Value::$xmlrpcDouble;
@@ -76,7 +76,7 @@ class Wrapper
      *
      * @return string
      */
-    public function xmlrpc_2_php_type($xmlrpcType)
+    public function xmlrpc2PhpType($xmlrpcType)
     {
         switch (strtolower($xmlrpcType)) {
             case 'base64':
@@ -85,6 +85,7 @@ class Wrapper
                 return Value::$xmlrpcString;
             case 'int':
             case 'i4':
+            case 'i8':
                 return 'integer';
             case 'struct':
             case 'array':
@@ -128,7 +129,7 @@ class Wrapper
      * php functions (ie. functions not expecting a single Request obj as parameter)
      * is by making use of the functions_parameters_type class member.
      *
-     * @param string|array $callable the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too
+     * @param callable $callable the PHP user function to be exposed as xmlrpc method/ a closure, function name, array($obj, 'methodname') or array('class', 'methodname') are ok
      * @param string $newFuncName (optional) name for function to be created. Used only when return_source in $extraOptions is true
      * @param array $extraOptions (optional) array of options for conversion. valid values include:
      *                            - bool return_source     when true, php code w. function definition will be returned, instead of a closure
@@ -148,7 +149,7 @@ class Wrapper
      * @todo add a verbatim_object_copy parameter to allow avoiding usage the same obj instance?
      * @todo add an option to allow generated function to skip validation of number of parameters, as that is done by the server anyway
      */
-    public function wrap_php_function($callable, $newFuncName = '', $extraOptions = array())
+    public function wrapPhpFunction($callable, $newFuncName = '', $extraOptions = array())
     {
         $buildIt = isset($extraOptions['return_source']) ? !($extraOptions['return_source']) : true;
 
@@ -175,8 +176,7 @@ class Wrapper
 
             $plainFuncName = 'Closure';
             $exists = true;
-        }
-        else {
+        } else {
             $plainFuncName = $callable;
             $exists = function_exists($callable);
         }
@@ -280,10 +280,10 @@ class Wrapper
                     $desc .= $doc;
                 } elseif (strpos($doc, '@param') === 0) {
                     // syntax: @param type $name [desc]
-                    if (preg_match('/@param\s+(\S+)\s+(\$\S+)\s+(.+)?/', $doc, $matches)) {
+                    if (preg_match('/@param\s+(\S+)\s+(\$\S+)\s*(.+)?/', $doc, $matches)) {
                         $name = strtolower(trim($matches[2]));
                         //$paramDocs[$name]['name'] = trim($matches[2]);
-                        $paramDocs[$name]['doc'] = $matches[3];
+                        $paramDocs[$name]['doc'] = isset($matches[3]) ? $matches[3] : '';
                         $paramDocs[$name]['type'] = $matches[1];
                     }
                     $i++;
@@ -367,12 +367,12 @@ class Wrapper
         $sigsDocs = array();
         foreach ($parsVariations as $pars) {
             // build a signature
-            $sig = array($this->php_2_xmlrpc_type($funcDesc['returns']));
+            $sig = array($this->php2XmlrpcType($funcDesc['returns']));
             $pSig = array($funcDesc['returnsDocs']);
             for ($i = 0; $i < count($pars); $i++) {
                 $name = strtolower($funcDesc['params'][$i]['name']);
                 if (isset($funcDesc['paramDocs'][$name]['type'])) {
-                    $sig[] = $this->php_2_xmlrpc_type($funcDesc['paramDocs'][$name]['type']);
+                    $sig[] = $this->php2XmlrpcType($funcDesc['paramDocs'][$name]['type']);
                 } else {
                     $sig[] = Value::$xmlrpcValue;
                 }
@@ -397,7 +397,7 @@ class Wrapper
      * @param array $extraOptions
      * @param string $plainFuncName
      * @param string $funcDesc
-     * @return callable
+     * @return \Closure
      */
     protected function buildWrapFunctionClosure($callable, $extraOptions, $plainFuncName, $funcDesc)
     {
@@ -498,7 +498,7 @@ class Wrapper
      * @param array $extraOptions
      * @param string $plainFuncName
      * @param array $funcDesc
-     * @return array
+     * @return string
      *
      * @todo add a nice phpdoc block in the generated source
      */
@@ -589,15 +589,15 @@ class Wrapper
      * PHP 'wrapper' functions that can be exposed as xmlrpc methods from an xmlrpc server
      * object and called from remote clients (as well as their corresponding signature info).
      *
-     * @param mixed $className the name of the class whose methods are to be exposed as xmlrpc methods, or an object instance of that class
-     * @param array $extraOptions see the docs for wrap_php_method for basic options, plus
+     * @param string|object $className the name of the class whose methods are to be exposed as xmlrpc methods, or an object instance of that class
+     * @param array $extraOptions see the docs for wrapPhpMethod for basic options, plus
      *                            - string method_type    'static', 'nonstatic', 'all' and 'auto' (default); the latter will switch between static and non-static depending on whether $className is a class name or object instance
      *                            - string method_filter  a regexp used to filter methods to wrap based on their names
      *                            - string prefix         used for the names of the xmlrpc methods created
      *
      * @return array|false false on failure
      */
-    public function wrap_php_class($className, $extraOptions = array())
+    public function wrapPhpClass($className, $extraOptions = array())
     {
         $methodFilter = isset($extraOptions['method_filter']) ? $extraOptions['method_filter'] : '';
         $methodType = isset($extraOptions['method_type']) ? $extraOptions['method_type'] : 'auto';
@@ -612,7 +612,7 @@ class Wrapper
                     if (($func->isStatic() && ($methodType == 'all' || $methodType == 'static' || ($methodType == 'auto' && is_string($className)))) ||
                         (!$func->isStatic() && ($methodType == 'all' || $methodType == 'nonstatic' || ($methodType == 'auto' && is_object($className))))
                     ) {
-                        $methodWrap = $this->wrap_php_function(array($className, $mName), '', $extraOptions);
+                        $methodWrap = $this->wrapPhpFunction(array($className, $mName), '', $extraOptions);
                         if ($methodWrap) {
                             if (is_object($className)) {
                                 $realClassName = get_class($className);
@@ -674,7 +674,7 @@ class Wrapper
      *
      * @return \closure|array|false false on failure, closure by default and array for return_source = true
      */
-    public function wrap_xmlrpc_method($client, $methodName, $extraOptions = array())
+    public function wrapXmlrpcMethod($client, $methodName, $extraOptions = array())
     {
         $newFuncName = isset($extraOptions['new_function_name']) ? $extraOptions['new_function_name'] : '';
 
@@ -786,7 +786,7 @@ class Wrapper
      * @param string $methodName
      * @param array $extraOptions
      * @param string $mSig
-     * @return callable
+     * @return \Closure
      *
      * @todo should we allow usage of parameter simple_client_copy to mean 'do not clone' in this case?
      */
@@ -822,7 +822,7 @@ class Wrapper
                 $decodeOptions[] = 'decode_php_objs';
             }
 
-            /// @todo check for insufficient nr. of args besides excess ones
+            /// @todo check for insufficient nr. of args besides excess ones? note that 'source' version does not...
 
             // support one extra parameter: debug
             $maxArgs = count($mSig)-1; // 1st element is the return type
@@ -835,11 +835,10 @@ class Wrapper
             $xmlrpcArgs = array();
             foreach($currentArgs as $i => $arg) {
                 if ($i == $maxArgs) {
-                    /// @todo log warning? check what happens with the 'source' version
                     break;
                 }
                 $pType = $mSig[$i+1];
-                if ($pType == 'i4' || $pType == 'int' || $pType == 'boolean' || $pType == 'double' ||
+                if ($pType == 'i4' || $pType == 'i8' || $pType == 'int' || $pType == 'boolean' || $pType == 'double' ||
                     $pType == 'string' || $pType == 'dateTime.iso8601' || $pType == 'base64' || $pType == 'null'
                 ) {
                     // by building directly xmlrpc values when type is known and scalar (instead of encode() calls),
@@ -873,7 +872,16 @@ class Wrapper
         return $function;
     }
 
-    protected function buildWrapMethodSource($client, $methodName, array $extraOptions, $newFuncName, $mSig, $mDesc='')
+    /**
+     * @param Client $client
+     * @param string $methodName
+     * @param array $extraOptions
+     * @param string $newFuncName
+     * @param array $mSig
+     * @param string $mDesc
+     * @return array
+     */
+    public function buildWrapMethodSource($client, $methodName, array $extraOptions, $newFuncName, $mSig, $mDesc='')
     {
         $timeout = isset($extraOptions['timeout']) ? (int)$extraOptions['timeout'] : 0;
         $protocol = isset($extraOptions['protocol']) ? $extraOptions['protocol'] : '';
@@ -895,7 +903,7 @@ class Wrapper
         if ($clientCopyMode < 2) {
             // client copy mode 0 or 1 == full / partial client copy in emitted code
             $verbatimClientCopy = !$clientCopyMode;
-            $innerCode = $this->build_client_wrapper_code($client, $verbatimClientCopy, $prefix, $namespace);
+            $innerCode = $this->buildClientWrapperCode($client, $verbatimClientCopy, $prefix, $namespace);
             $innerCode .= "\$client->setDebug(\$debug);\n";
             $this_ = '';
         } else {
@@ -919,7 +927,7 @@ class Wrapper
         for ($i = 1; $i < $pCount; $i++) {
             $plist[] = "\$p$i";
             $pType = $mSig[$i];
-            if ($pType == 'i4' || $pType == 'int' || $pType == 'boolean' || $pType == 'double' ||
+            if ($pType == 'i4' || $pType == 'i8' || $pType == 'int' || $pType == 'boolean' || $pType == 'double' ||
                 $pType == 'string' || $pType == 'dateTime.iso8601' || $pType == 'base64' || $pType == 'null'
             ) {
                 // only build directly xmlrpc values when type is known and scalar
@@ -932,14 +940,14 @@ class Wrapper
                 }
             }
             $innerCode .= "\$req->addparam(\$p$i);\n";
-            $mDesc .= '* @param ' . $this->xmlrpc_2_php_type($pType) . " \$p$i\n";
+            $mDesc .= '* @param ' . $this->xmlrpc2PhpType($pType) . " \$p$i\n";
         }
         if ($clientCopyMode < 2) {
             $plist[] = '$debug=0';
             $mDesc .= "* @param int \$debug when 1 (or 2) will enable debugging of the underlying {$prefix} call (defaults to 0)\n";
         }
         $plist = implode(', ', $plist);
-        $mDesc .= '* @return ' . $this->xmlrpc_2_php_type($mSig[0]) . " (or an {$namespace}Response obj instance if call fails)\n*/\n";
+        $mDesc .= '* @return ' . $this->xmlrpc2PhpType($mSig[0]) . " (or an {$namespace}Response obj instance if call fails)\n*/\n";
 
         $innerCode .= "\$res = \${$this_}client->send(\$req, $timeout, '$protocol');\n";
         if ($decodeFault) {
@@ -963,24 +971,24 @@ class Wrapper
     }
 
     /**
-     * Similar to wrap_xmlrpc_method, but will generate a php class that wraps
+     * Similar to wrapXmlrpcMethod, but will generate a php class that wraps
      * all xmlrpc methods exposed by the remote server as own methods.
-     * For more details see wrap_xmlrpc_method.
+     * For more details see wrapXmlrpcMethod.
      *
      * For a slimmer alternative, see the code in demo/client/proxy.php
      *
-     * Note that unlike wrap_xmlrpc_method, we always have to generate php code here. It seems that php 7 will have anon classes...
+     * Note that unlike wrapXmlrpcMethod, we always have to generate php code here. It seems that php 7 will have anon classes...
      *
      * @param Client $client the client obj all set to query the desired server
-     * @param array $extraOptions list of options for wrapped code. See the ones from wrap_xmlrpc_method plus
+     * @param array $extraOptions list of options for wrapped code. See the ones from wrapXmlrpcMethod plus
      *              - string method_filter      regular expression
      *              - string new_class_name
      *              - string prefix
      *              - bool   simple_client_copy set it to true to avoid copying all properties of $client into the copy made in the new class
      *
-     * @return mixed false on error, the name of the created class if all ok or an array with code, class name and comments (if the appropriatevoption is set in extra_options)
+     * @return mixed false on error, the name of the created class if all ok or an array with code, class name and comments (if the appropriate option is set in extra_options)
      */
-    public function wrap_xmlrpc_server($client, $extraOptions = array())
+    public function wrapXmlrpcServer($client, $extraOptions = array())
     {
         $methodFilter = isset($extraOptions['method_filter']) ? $extraOptions['method_filter'] : '';
         $timeout = isset($extraOptions['timeout']) ? (int)$extraOptions['timeout'] : 0;
@@ -1027,7 +1035,7 @@ class Wrapper
                 /// @todo add function setdebug() to new class, to enable/disable debugging
                 $source = "class $xmlrpcClassName\n{\npublic \$client;\n\n";
                 $source .= "function __construct()\n{\n";
-                $source .= $this->build_client_wrapper_code($client, $verbatimClientCopy, $prefix, $namespace);
+                $source .= $this->buildClientWrapperCode($client, $verbatimClientCopy, $prefix, $namespace);
                 $source .= "\$this->client = \$client;\n}\n\n";
                 $opts = array(
                     'return_source' => true,
@@ -1044,7 +1052,7 @@ class Wrapper
                         // note: this will fail if server exposes 2 methods called f.e. do.something and do_something
                         $opts['new_function_name'] = preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
                             array('_', ''), $mName);
-                        $methodWrap = $this->wrap_xmlrpc_method($client, $mName, $opts);
+                        $methodWrap = $this->wrapXmlrpcMethod($client, $mName, $opts);
                         if ($methodWrap) {
                             if (!$buildIt) {
                                 $source .= $methodWrap['docstring'];
@@ -1083,7 +1091,7 @@ class Wrapper
      *
      * @return string
      */
-    protected function build_client_wrapper_code($client, $verbatimClientCopy, $prefix = 'xmlrpc', $namespace = '\\PhpXmlRpc\\' )
+    protected function buildClientWrapperCode($client, $verbatimClientCopy, $prefix = 'xmlrpc', $namespace = '\\PhpXmlRpc\\' )
     {
         $code = "\$client = new {$namespace}Client('" . str_replace("'", "\'", $client->path) .
             "', '" . str_replace("'", "\'", $client->server) . "', $client->port);\n";