make all (most?) object propeties and add compatibility accessors
authorgggeek <giunta.gaetano@gmail.com>
Sat, 4 Feb 2023 11:13:41 +0000 (11:13 +0000)
committergggeek <giunta.gaetano@gmail.com>
Sat, 4 Feb 2023 11:13:41 +0000 (11:13 +0000)
NEWS.md
doc/api_changes_v4.10.md [new file with mode: 0644]
lib/xmlrpcs.inc
src/Client.php
src/Helper/XMLParser.php
src/PhpXmlRpc.php
src/Request.php
src/Response.php
src/Server.php
src/Traits/PayloadBearer.php
src/Value.php

diff --git a/NEWS.md b/NEWS.md
index 7dd7bd3..e2efc99 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,6 +4,12 @@
 
 * changed: dropped support for parsing cookie headers which follow the obsolete Cookie2 specification
 
+* new: it is now possible to make the library generate warning messages whenever a deprecated feature is used, such as
+  calling deprecated methods, using deprecated method parameters, or reading/writing deprecated object properties.
+  This is disabled by default, and can be enabled by setting `PhpXmlRpc\PhpXmlRpc::xmlrpc_silence_deprecations = false`.
+  Note that the deprecation warnings will be by default added to the php error log, and not be displayed on screen.
+  If you prefer them to be handled in some other way, you should take over the Logger, as described below here
+
 * new: allow to specify other charsets than the canonical three (UTF-8, ISO-8859-1, ASCII), when mbstring is
   available, both for outgoing and incoming data (issue #42).
 
@@ -54,6 +60,8 @@
   a method handler in the dispatch was defined with `'parameters_type' = 'phpvals'`, the handler would be passed a
   Request object instead of plain php values.
 
+* fixed: made sure all debug output goes through the logger at response parsing time (there was one printf call left)
+
 * fixed: when calling `Client::multicall()` with `$client->return_type = 'xml'`, the code would be always falling back to
   non-multicall requests
 
 * new: added methods `getOption`, `setOption`, `setOptions` and `getOptions` to both Client and Server, meant to replace
   direct access to _all public properties_ as well as the `$timeout` argument in calls to `Client::send` and `Client::multicall`
 
-* new: it is now possible to make the library generate warning messages whenever a deprecated feature is used, such as
-  calling deprecated methods, using deprecated method parameters, or reading/writing deprecated object properties.
-  This is disabled by default, and can be enabled by setting `PhpXmlRpc\PhpXmlRpc::xmlrpc_silence_deprecations = false`.
-  Note that the deprecation warnings will be by default added to the php error log, and not be displayed on screen.
-  If you prefer them to be handled in some other way, you should take over the Logger, as described just below here
-
 * new: it is now possible to inject a custom logger into helper classes `Charset`, `Http`, `XMLParser`, inching a step
   closer to supporting DIC patterns (issue #78)
 
@@ -94,8 +96,6 @@
 
 * improved: the `Logger` class now sports methods adhering to Psr\Log\LoggerInterface
 
-* improved: made sure all debug output goes through the logger at response parsing time (there was one printf call left)
-
 * improved: limit the size of incoming data which will be used in error responses and logged error messages, making
   it slightly harder to carry out DOS attacks against the library
 
 
 * improved: made sure the test container and gha test runners have at least one locale with comma as decimal separator
 
-* BC notes (besides what can be inferred from the changes listed above):
+* BC notes:
+
+  *NB* Given the considerable amount of API changes in this release, a set of tables listing every change has been
+  added in doc/api_changes_v4.10.md; a textual description follows.
 
-  for library users
+  Besides what can be inferred from the changes listed above, for library users:
 
   - the data passed to the application is not encoded anymore in UTF-8 when setting `PhpXmlRpc::$internal_encoding`
     to a custom character set and the mbstring extension is enabled. It will be encoded instead in the specified character
   - the code generated by the debugger when using "Generate stub for method call" will throw on errors instead of
     returning a Response object
 
-  for library extenders
+  For library extenders:
 
   - the `$options` argument passed to `XMLParser::parse` will now contain both options intended to be passed down to
     the php xml parser, and further options used to tweak the parsing results. If you have subclassed `XMLParser`
   - new methods in helper classes: `Charset::knownCharsets`, `Http::parseAcceptHeader`, `XMLParser::truncateValueForLog`
   - exception `\PhpXmlRpc\Exception\PhpXmlRpcException` is deprecated. Use `\PhpXmlRpc\Exception` instead
 
+
 ## XML-RPC for PHP version 4.9.5 - 2023/01/11
 
 * improved: revised all demo files. Showcase more features in client demos; isolate better testsuite functions in
diff --git a/doc/api_changes_v4.10.md b/doc/api_changes_v4.10.md
new file mode 100644 (file)
index 0000000..8264e6c
--- /dev/null
@@ -0,0 +1,194 @@
+API Changes between library versions 4.9 and 4.10
+=================================================
+
+While 4.10 keeps the usual BC promise with previous 4.x releases, it also paves the way for all the API changes foreseen
+to happen in future version 5.
+
+In particular, API cleanups mean that most public access to object properties has been replaced by dedicated methods.
+
+New classes, traits, exceptions
+-------------------------------
+
+For the first time, usage of custom exceptions is in place. Traits are also in use for sharing common functionality.
+
+| Type      | Name                          | Notes                                                               |
+|-----------|-------------------------------|---------------------------------------------------------------------|
+| exception | PhpXmlRpc\Exception           | Parent class for all exceptions thrown by the library.              |
+|           |                               | Its alias PhpXmlRpc\Exception\PhpXmlRpcException is still in place. |
+| exception | PhpXmlRpc\Exception\...       | See the list in the appendix of the user manual                     |
+| trait     | PhpXmlRpc\CharsetEncoderAware |                                                                     |
+| trait     | PhpXmlRpc\Server              |                                                                     |
+| trait     | PhpXmlRpc\DeprecationLogger   |                                                                     |
+| trait     | PhpXmlRpc\ParserAware         |                                                                     |
+| trait     | PhpXmlRpc\PayloadBearer       |                                                                     |
+
+New class methods
+-----------------
+
+In case you had extended the classes of the library and added methods to the subclasses, you might find that your
+implementation clashes with the new one if you implemented:
+
+| Class     | Method              | Notes     |
+|-----------|---------------------|-----------|
+| *         | __get               |           |
+| *         | __isset             |           |
+| *         | __set               |           |
+| *         | __unset             |           |
+| Charset   | getLogger           |           |
+| Charset   | knownCharsets       |           |
+| Charset   | setLogger           | static    |
+| Client    | getOption           |           |
+| Client    | getOptions          |           |
+| Client    | getUrl              |           |
+| Client    | setOption           |           |
+| Client    | setOptions          |           |
+| Http      | getLogger           |           |
+| Http      | parseAcceptHeader   |           |
+| Http      | setLogger           | static    |
+| Logger    | debug               |           |
+| Logger    | error               |           |
+| Logger    | warning             |           |
+| PhpXmlRpc | setLogger           | static    |
+| PhpXmlRpc | useInteropFaults    | static    |
+| Request   | getContentType      |           |
+| Request   | getPayload          |           |
+| Response  | getContentType      |           |
+| Response  | getPayload          |           |
+| Response  | valueType           |           |
+| Response  | xml_header          |           |
+| Server    | getOption           |           |
+| Server    | getOptions          |           |
+| Server    | setDispatchMap      |           |
+| Server    | setOption           |           |
+| Server    | setOptions          |           |
+| Wrapper   | getHeldObject       |           |
+| Wrapper   | holdObject          |           |
+| XMLParser | getLogger           |           |
+| XMLParser | setLogger           | static    |
+| XMLParser | truncateValueForLog | protected |
+
+New class properties
+--------------------
+
+| Class     | Property | Default value | Notes     |
+|-----------|----------|---------------|-----------|
+| Client    | $timeout | 0             | protected |
+
+New static properties
+---------------------
+
+| Class     | Property                      | Default value       | Notes     |
+|-----------|-------------------------------|---------------------|-----------|
+| Client    | $options                      | see code            | protected |
+| Client    | $requestClass                 | \PhpXmlRpc\Request  | protected |
+| Client    | $responseClass                | \PhpXmlRpc\Response | protected |
+| PhpXmlRpc | $xmlrpc_datetime_format       | see code            |           |
+| PhpXmlRpc | $xmlrpc_double_format         | see code            |           |
+| PhpXmlRpc | $xmlrpc_int_format            | see code            |           |
+| PhpXmlRpc | $xmlrpc_methodname_format     | see code            |           |
+| PhpXmlRpc | $xmlrpc_reject_invalid_values | false               |           |
+| PhpXmlRpc | $xmlrpc_return_datetimes      | false               |           |
+| PhpXmlRpc | $xmlrpc_silence_deprecations  | true                |           |
+
+New constants
+-------------
+
+| Class  | Constant | Notes                 |
+|--------|----------|-----------------------|
+| Client | OPT_*    | see code for the list |
+| Server | OPT_*    | see code for the list |
+
+Changed methods
+---------------
+
+The following methods acquired new parameters, or accept a wider range of values for existing parameters
+
+| Class     | Method   | Notes |
+|-----------|----------|-------|
+| PhpXmlRpc | $xmlrpc_ |       |
+
+Deprecated methods
+---------------------
+
+| Class   | Method                | Replacement          |
+|---------|-----------------------|----------------------|
+| Charset | isValidCharset        | -                    |
+| Client  | prepareCurlHandle     | createCURLHandle     |
+| Client  | sendPayloadCurl       | sendViaCURL          |
+| Client  | sendPayloadSocket     | sendViaSocket        |
+| Client  | setCurlOptions        | setOption            |
+| Client  | setRequestCompression | setOption            |
+| Client  | setSSLVerifyHost      | setOption            |
+| Client  | setSSLVerifyPeer      | setOption            |
+| Client  | setSSLVersion         | setOption            |
+| Client  | setUseCurl            | setOption            |
+| Client  | setUserAgent          | setOption            |
+| Server  | xml_header            | Response::xml_header |
+| Value   | serializeData         | -                    |
+
+Deprecated properties
+---------------------
+
+The following properties have now protected access. Replacement accessor for public use are listed.
+
+| Class    | Property                   | Read via               | Write via                        |
+|----------|----------------------------|------------------------|----------------------------------|
+| Client   | accepted_charset_encodings | getOption              | setOption                        |
+| Client   | accepted_compression       | getOption              | setOption/setAcceptedCompression |
+| Client   | authtype                   | getOption              | setOption/setCredentials         |
+| Client   | cacert                     | getOption              | setOption/setCaCertificate       |
+| Client   | cacertdir                  | getOption              | setOption/setCaCertificate       |
+| Client   | cert                       | getOption              | setOption/setCertificate         |
+| Client   | certpass                   | getOption              | setOption/setCertificate         |
+| Client   | cookies                    | getOption              | setOption                        |
+| Client   | debug                      | getOption              | setOption/setDebug               |
+| Client   | errno                      | -                      | -                                |
+| Client   | errstr                     | -                      | -                                |
+| Client   | extracurlopts              | getOption              | setOption                        |
+| Client   | keepalive                  | getOption              | setOption                        |
+| Client   | key                        | getOption              | setOption/setKey                 |
+| Client   | keypass                    | getOption              | setOption/setKey                 |
+| Client   | method                     | getUrl                 | __construct                      |
+| Client   | no_multicall               | getOption              | setOption                        |
+| Client   | password                   | getOption              | setOption/setCredentials         |
+| Client   | path                       | getUrl                 | __construct                      |
+| Client   | port                       | getUrl                 | __construct                      |
+| Client   | proxy                      | getOption              | setOption/setProxy               |
+| Client   | proxy_authtype             | getOption              | setOption/setProxy               |
+| Client   | proxy_pass                 | getOption              | setOption/setProxy               |
+| Client   | proxy_user                 | getOption              | setOption/setProxy               |
+| Client   | proxyport                  | getOption              | setOption/setProxy               |
+| Client   | request_charset_encoding   | getOption              | setOption                        |
+| Client   | request_compression        | getOption              | setOption                        |
+| Client   | return_type                | getOption              | setOption                        |
+| Client   | server                     | getUrl                 | __construct                      |
+| Client   | sslversion                 | getOption              | setOption                        |
+| Client   | use_curl                   | getOption              | setOption                        |
+| Client   | user_agent                 | getOption              | setOption                        |
+| Client   | username                   | getOption              | setOption/setCredentials         |
+| Client   | verifyhost                 | getOption              | setOption                        |
+| Client   | verifypeer                 | getOption              | setOption                        |
+| Request  | content_type               | getContentType         | setPayload                       |
+| Request  | debug                      | setDebug               | -                                |
+| Request  | methodname                 | method                 | __construct/method               |
+| Request  | params                     | getParam               | __construct/addParam             |
+| Request  | payload                    | getPayload             | setPayload                       |
+| Response | val                        | value                  | __construct                      |
+| Response | valtyp                     | valueType              | __construct                      |
+| Response | errno                      | faultCode              | __construct                      |
+| Response | errstr                     | faultString            | __construct                      |
+| Response | content_type               | getContentType         | setPayload                       |
+| Response | payload                    | getPayload             | setPayload                       |
+| Server   | accepted_charset_encodings | -                      | -                                |
+| Server   | accepted_compression       | getOption              | setOption                        |
+| Server   | allow_system_funcs         | getOption              | setOption                        |
+| Server   | compress_response          | getOption              | setOption                        |
+| Server   | debug                      | getOption              | setOption/setDebug               |
+| Server   | exception_handling         | getOption              | setOption                        |
+| Server   | functions_parameters_type  | getOption              | setOption                        |
+| Server   | phpvals_encoding_options   | getOption              | setOption                        |
+| Server   | response_charset_encoding  | getOption              | setOption                        |
+| Value    | _php_class                 | -                      | -                                |
+| Value    | me                         | scalarVal/array access | __construct                      |
+| Value    | mytype                     | kindOf                 | __construct                      |
+| Wrapper  | $objectholder              | getHeldObject          | holdObject                       |
index 77abb79..cf5a88b 100644 (file)
@@ -69,10 +69,7 @@ class xmlrpc_server extends Server
             case 'dmap':
                 return $this->dmap;
             default:
-                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
-                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' .
-                    $trace[0]['line'], E_USER_NOTICE);
-                return null;
+                return parent::__get($name);
         }
     }
 
@@ -82,7 +79,7 @@ class xmlrpc_server extends Server
      */
     public function __isset($name)
     {
-        return $name === 'dmap';
+        return $name === 'dmap' ? true : parent::__isset($name);
     }
 
     /// @todo what about __set, __unset?
index 9fa488e..076cdce 100644 (file)
@@ -2,17 +2,25 @@
 
 namespace PhpXmlRpc;
 
-//use PhpXmlRpc\Helper\Charset;
 use PhpXmlRpc\Exception\ValueErrorException;
 use PhpXmlRpc\Helper\XMLParser;
+use PhpXmlRpc\Traits\CharsetEncoderAware;
 use PhpXmlRpc\Traits\DeprecationLogger;
 
 /**
  * Used to represent a client of an XML-RPC server.
+ *
+ * @property int $errno deprecated - public access left in purely for BC.
+ * @property string $errstr deprecated - public access left in purely for BC.
+ * @property string $method deprecated - public access left in purely for BC. Access via getUrl()/__construct()
+ * @property string $server deprecated - public access left in purely for BC. Access via getUrl()/__construct()
+ * @property int $port deprecated - public access left in purely for BC. Access via getUrl()/__construct()
+ * @property string $path deprecated - public access left in purely for BC. Access via getUrl()/__construct()
  */
 class Client
 {
     use DeprecationLogger;
+    //use CharsetEncoderAware;
 
     const USE_CURL_NEVER = 0;
     const USE_CURL_ALWAYS = 1;
@@ -58,12 +66,12 @@ class Client
      * @var int
      * @deprecated will be removed in the future
      */
-    public $errno;
+    protected $errno;
     /**
      * @var string
      * @deprecated will be removed in the future
      */
-    public $errstr;
+    protected $errstr;
 
     /// @todo: do all the ones below need to be public?
 
@@ -71,133 +79,133 @@ class Client
      * @var string
      * @internal use getUrl/__construct
      */
-    public $method = 'http';
+    protected $method = 'http';
     /**
      * @var string
      * @internal use getUrl/__construct
      */
-    public $server;
+    protected $server;
     /**
      * @var int
      * @internal use getUrl/__construct
      */
-    public $port = 0;
+    protected $port = 0;
     /**
      * @var string
      * @internal use getUrl/__construct
      */
-    public $path;
+    protected $path;
 
     /**
      * @var int
      * @internal use setOption/getOption
      */
-    public $debug = 0;
+    protected $debug = 0;
     /**
      * @var string
      * @internal use setCredentials/getOption
      */
-    public $username = '';
+    protected $username = '';
     /**
      * @var string
      * @internal use setCredentials/getOption
      */
-    public $password = '';
+    protected $password = '';
     /**
      * @var int
      * @internal use setCredentials/getOption
      */
-    public $authtype = 1;
+    protected $authtype = 1;
     /**
      * @var string
      * @internal use setCertificate/getOption
      */
-    public $cert = '';
+    protected $cert = '';
     /**
      * @var string
      * @internal use setCertificate/getOption
      */
-    public $certpass = '';
+    protected $certpass = '';
     /**
      * @var string
      * @internal use setCaCertificate/getOption
      */
-    public $cacert = '';
+    protected $cacert = '';
     /**
      * @var string
      * @internal use setCaCertificate/getOption
      */
-    public $cacertdir = '';
+    protected $cacertdir = '';
     /**
      * @var string
      * @internal use setKey/getOption
      */
-    public $key = '';
+    protected $key = '';
     /**
      * @var string
      * @internal use setKey/getOption
      */
-    public $keypass = '';
+    protected $keypass = '';
     /**
      * @var bool
      * @internal use setOption/getOption
      */
-    public $verifypeer = true;
+    protected $verifypeer = true;
     /**
      * @var int
      * @internal use setOption/getOption
      */
-    public $verifyhost = 2;
+    protected $verifyhost = 2;
     /**
      * @var int
      * @internal use setOption/getOption
      */
-    public $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT
+    protected $sslversion = 0; // corresponds to CURL_SSLVERSION_DEFAULT
     /**
      * @var string
      * @internal use setProxy/getOption
      */
-    public $proxy = '';
+    protected $proxy = '';
     /**
      * @var int
      * @internal use setProxy/getOption
      */
-    public $proxyport = 0;
+    protected $proxyport = 0;
     /**
      * @var string
      * @internal use setProxy/getOption
      */
-    public $proxy_user = '';
+    protected $proxy_user = '';
     /**
      * @var string
      * @internal use setProxy/getOption
      */
-    public $proxy_pass = '';
+    protected $proxy_pass = '';
     /**
      * @var int
      * @internal use setProxy/getOption
      */
-    public $proxy_authtype = 1;
+    protected $proxy_authtype = 1;
     /**
      * @var array
      * @internal use setCookie/getOption
      */
-    public $cookies = array();
+    protected $cookies = array();
     /**
      * @var array
      * @internal use setOption/getOption
      */
-    public $extracurlopts = array();
+    protected $extracurlopts = array();
     /**
      * @var int
      * @internal use setOption/getOption
      */
-    public $timeout = 0;
+    protected $timeout = 0;
     /**
      * @var int
      * @internal use setOption/getOption
      */
-    public $use_curl = self::USE_CURL_AUTO;
+    protected $use_curl = self::USE_CURL_AUTO;
     /**
      * @var bool
      *
@@ -208,7 +216,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $no_multicall = false;
+    protected $no_multicall = false;
     /**
      * @var array
      *
@@ -221,7 +229,7 @@ class Client
      *
      * @internal use setAcceptedCompression/getOption
      */
-    public $accepted_compression = array();
+    protected $accepted_compression = array();
     /**
      * @var string|null
      *
@@ -230,7 +238,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $request_compression = '';
+    protected $request_compression = '';
     /**
      * @var bool
      *
@@ -238,7 +246,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $keepalive = false;
+    protected $keepalive = false;
     /**
      * @var string[]
      *
@@ -246,7 +254,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $accepted_charset_encodings = array();
+    protected $accepted_charset_encodings = array();
     /**
      * @var string
      *
@@ -259,7 +267,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $request_charset_encoding = '';
+    protected $request_charset_encoding = '';
     /**
      * @var string
      *
@@ -277,7 +285,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $return_type = XMLParser::RETURN_XMLRPCVALS;
+    protected $return_type = XMLParser::RETURN_XMLRPCVALS;
     /**
      * @var string
      *
@@ -285,7 +293,7 @@ class Client
      *
      * @internal use setOption/getOption
      */
-    public $user_agent;
+    protected $user_agent;
 
     /**
      * CURL handle: used for keep-alive
@@ -296,7 +304,7 @@ class Client
     /**
      * @var array
      */
-    protected $options = array(
+    protected static $options = array(
         self::OPT_ACCEPTED_CHARSET_ENCODINGS,
         self::OPT_ACCEPTED_COMPRESSION,
         self::OPT_AUTH_TYPE,
@@ -401,7 +409,7 @@ class Client
         $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
 
         // NB: this is disabled to avoid making all the requests sent huge... mbstring supports more than 80 charsets!
-        //$ch = Charset::instance();
+        //$ch = $this->getCharsetEncoder();
         //$this->accepted_charset_encodings = $ch->knownCharsets();
 
         // initialize user_agent string
@@ -416,102 +424,12 @@ class Client
      */
     public function setOption($name, $value)
     {
-        switch ($name) {
-            case self::OPT_ACCEPTED_CHARSET_ENCODINGS:
-                $this->accepted_charset_encodings = $value;
-                break;
-            case self::OPT_ACCEPTED_COMPRESSION:
-                $this->accepted_compression = $value;
-                break;
-            case self::OPT_AUTH_TYPE:
-                $this->authtype = $value;
-                break;
-            case self::OPT_CA_CERT:
-                $this->cacert = $value;
-                break;
-            case self::OPT_CA_CERT_DIR:
-                $this->cacertdir = $value;
-                break;
-            case self::OPT_CERT:
-                $this->cert = $value;
-                break;
-            case self::OPT_CERT_PASS:
-                $this->certpass = $value;
-                break;
-            case self::OPT_COOKIES:
-                $this->cookies = $value;
-                break;
-            case self::OPT_DEBUG:
-                $this->debug = $value;
-                break;
-            case self::OPT_EXTRA_CURL_OPTS:
-                $this->extracurlopts = $value;
-                break;
-            case self::OPT_KEEPALIVE:
-                $this->keepalive = $value;
-                break;
-            case self::OPT_KEY:
-                $this->key = $value;
-                break;
-            case self::OPT_KEY_PASS:
-                $this->keypass = $value;
-                break;
-            case self::OPT_NO_MULTICALL:
-                $this->no_multicall = $value;
-                break;
-            case self::OPT_PASSWORD:
-                $this->password = $value;
-                break;
-            case self::OPT_PROXY:
-                $this->proxy = $value;
-                break;
-            case self::OPT_PROXY_AUTH_TYPE:
-                $this->proxy_authtype = $value;
-                break;
-            case self::OPT_PROXY_PASS:
-                $this->proxy_pass = $value;
-                break;
-            case self::OPT_PROXY_PORT:
-                $this->proxyport = $value;
-                break;
-            case self::OPT_PROXY_USER:
-                $this->proxy_user = $value;
-                break;
-            case self::OPT_REQUEST_CHARSET_ENCODING:
-                $this->request_charset_encoding = $value;
-                break;
-            case self::OPT_REQUEST_COMPRESSION:
-                $this->request_compression = $value;
-                break;
-            case self::OPT_RETURN_TYPE:
-                $this->return_type = $value;
-                break;
-            case self::OPT_SSL_VERSION:
-                $this->sslversion = $value;
-                break;
-            case self::OPT_TIMEOUT:
-                $this->timeout = $value;
-                break;
-            case self::OPT_USERNAME:
-                $this->username = $value;
-                break;
-            case self::OPT_USER_AGENT:
-                $this->user_agent = $value;
-                break;
-            case self::OPT_USE_CURL:
-                $this->use_curl = $value;
-                break;
-            case self::OPT_VERIFY_HOST:
-                $this->verifyhost = $value;
-                break;
-            case self::OPT_VERIFY_PEER:
-                $this->verifypeer = $value;
-                break;
-            default:
-                throw new ValueErrorException("Unsupported option '$name'");
+        if (in_array($name, static::$options)) {
+            $this->$name = $value;
+            return $this;
         }
 
-        return $this;
+        throw new ValueErrorException("Unsupported option '$name'");
     }
 
     /**
@@ -521,70 +439,11 @@ class Client
      */
     public function getOption($name)
     {
-        switch ($name) {
-            case self::OPT_ACCEPTED_CHARSET_ENCODINGS:
-                return $this->accepted_charset_encodings;
-            case self::OPT_ACCEPTED_COMPRESSION:
-                return $this->accepted_compression;
-            case self::OPT_AUTH_TYPE:
-                return $this->authtype;
-            case self::OPT_CA_CERT:
-                return $this->cacert;
-            case self::OPT_CA_CERT_DIR:
-                return $this->cacertdir;
-            case self::OPT_CERT:
-                return $this->cert;
-            case self::OPT_CERT_PASS:
-                return $this->certpass;
-            case self::OPT_COOKIES:
-                return $this->cookies;
-            case self::OPT_DEBUG:
-                return $this->debug;
-            case self::OPT_EXTRA_CURL_OPTS:
-                return $this->extracurlopts;
-            case self::OPT_KEEPALIVE:
-                return $this->keepalive;
-            case self::OPT_KEY:
-                return $this->key;
-            case self::OPT_KEY_PASS:
-                return $this->keypass;
-            case self::OPT_NO_MULTICALL:
-                return $this->no_multicall;
-            case self::OPT_PASSWORD:
-                return $this->password;
-            case self::OPT_PROXY:
-                return $this->proxy;
-            case self::OPT_PROXY_AUTH_TYPE:
-                return $this->proxy_authtype;
-            case self::OPT_PROXY_PASS:
-                return $this->proxy_pass;
-            case self::OPT_PROXY_PORT:
-                return $this->proxyport;
-            case self::OPT_PROXY_USER:
-                return $this->proxy_user;
-            case self::OPT_REQUEST_CHARSET_ENCODING:
-                return $this->request_charset_encoding;
-            case self::OPT_REQUEST_COMPRESSION:
-                return $this->request_compression;
-            case self::OPT_RETURN_TYPE:
-                return $this->return_type;
-            case self::OPT_SSL_VERSION:
-                return $this->sslversion;
-            case self::OPT_TIMEOUT:
-                return $this->timeout;
-            case self::OPT_USERNAME:
-                return $this->username;
-            case self::OPT_USER_AGENT:
-                return $this->user_agent;
-            case self::OPT_USE_CURL:
-                return $this->use_curl;
-            case self::OPT_VERIFY_HOST:
-                return $this->verifyhost;
-            case self::OPT_VERIFY_PEER:
-                return $this->verifypeer;
-            default:
-                throw new ValueErrorException("Unsupported option '$name'");
+        if (in_array($name, static::$options)) {
+            return $this->$name;
         }
+
+        throw new ValueErrorException("Unsupported option '$name'");
     }
 
     /**
@@ -594,7 +453,7 @@ class Client
     public function getOptions()
     {
         $values = array();
-        foreach ($this->options as $opt) {
+        foreach (static::$options as $opt) {
             $values[$opt] = $this->getOption($opt);
         }
         return $values;
@@ -1349,7 +1208,7 @@ class Client
      * @param array $opts the keys/values match self::getOptions
      * @return \CurlHandle|resource|false
      */
-    protected function createCurlHandle($req, $method, $server, $port, $path, $opts)
+    protected function createCURLHandle($req, $method, $server, $port, $path, $opts)
     {
         if ($port == 0) {
             if (in_array($method, array('http', 'http10', 'http11', 'h2c'))) {
@@ -2018,7 +1877,7 @@ class Client
     {
         $this->logDeprecationUnlessCalledBy('sendViaCURL');
 
-        return $this->createCurlHandle($req, $method, $server, $port, $this->path, array(
+        return $this->createCURLHandle($req, $method, $server, $port, $this->path, array(
             'accepted_charset_encodings' => $this->accepted_charset_encodings,
             'accepted_compression' => $this->accepted_compression,
             'authtype' => $authType,
@@ -2051,4 +1910,101 @@ class Client
             'verifypeer' => $this->verifypeer,
         ));
     }
+
+    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
+    public function &__get($name)
+    {
+        if (in_array($name, static::$options)) {
+            $this->logDeprecation('Getting property Client::' . $name . ' is deprecated');
+            return $this->$name;
+        }
+
+        switch ($name) {
+            case 'errno':
+            case 'errstr':
+            case 'method':
+            case 'server':
+            case 'port':
+            case 'path':
+                $this->logDeprecation('Getting property Client::' . $name . ' is deprecated');
+                return $this->$name;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+                $result = null;
+                return $result;
+        }
+    }
+
+    public function __set($name, $value)
+    {
+        if (in_array($name, static::$options)) {
+            $this->logDeprecation('Setting property Client::' . $name . ' is deprecated');
+            $this->$name = $value;
+            return;
+        }
+
+        switch ($name) {
+            case 'errno':
+            case 'errstr':
+            case 'method':
+            case 'server':
+            case 'port':
+            case 'path':
+                $this->logDeprecation('Setting property Client::' . $name . ' is deprecated');
+                $this->$name = $value;
+                return;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
+
+    public function __isset($name)
+    {
+        if (in_array($name, static::$options)) {
+            $this->logDeprecation('Checking property Client::' . $name . ' is deprecated');
+            return isset($this->$name);
+        }
+
+        switch ($name) {
+            case 'errno':
+            case 'errstr':
+            case 'method':
+            case 'server':
+            case 'port':
+            case 'path':
+                $this->logDeprecation('Checking property Client::' . $name . ' is deprecated');
+                return isset($this->$name);
+            default:
+                return false;
+        }
+    }
+
+    public function __unset($name)
+    {
+        if (in_array($name, static::$options)) {
+            $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated');
+            unset($this->$name);
+            return;
+        }
+
+        switch ($name) {
+            case 'errno':
+            case 'errstr':
+            case 'method':
+            case 'server':
+            case 'port':
+            case 'path':
+                $this->logDeprecation('Unsetting property Client::' . $name . ' is deprecated');
+                unset($this->$name);
+                return;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
 }
index 39cb8d0..167a880 100644 (file)
@@ -17,6 +17,9 @@ use PhpXmlRpc\Value;
  * @todo if iconv() or mb_string() are available, we could allow to convert the received xml to a custom charset encoding
  *       while parsing, which is faster than doing it later by going over the rebuilt data structure
  * @todo rename? This is an xml-rpc parser, not a generic xml parser...
+ *
+ * @property array $xmlrpc_valid_parents deprecated - public access left in purely for BC
+ * @property int $accept deprecated - (protected) access left in purely for BC
  */
 class XMLParser
 {
@@ -72,9 +75,8 @@ class XMLParser
 
     /**
      * @var array[]
-     * @internal
      */
-    public $xmlrpc_valid_parents = array(
+    protected $xmlrpc_valid_parents = array(
         'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
         'BOOLEAN' => array('VALUE'),
         'I4' => array('VALUE'),
@@ -1015,6 +1017,21 @@ class XMLParser
         $this->xmlrpc_se($parser, $name, $attrs, true);
     }
 
+    public function &__get($name)
+    {
+        switch ($name) {
+            case 'xmlrpc_valid_parents':
+                $this->logDeprecation('Getting property XMLParser::' . $name . ' is deprecated');
+                return $this->$name;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+                $result = null;
+                return $result;
+        }
+    }
+
     public function __set($name, $value)
     {
         switch ($name) {
@@ -1023,6 +1040,10 @@ class XMLParser
                 $this->logDeprecation('Setting property XMLParser::' . $name . ' is deprecated');
                 $this->current_parsing_options['accept'] = $value;
                 break;
+            case 'xmlrpc_valid_parents':
+                $this->logDeprecation('Setting property XMLParser::' . $name . ' is deprecated');
+                $this->$name = $value;
+                break;
             default:
                 /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
                 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
@@ -1036,6 +1057,9 @@ class XMLParser
             case 'accept':
                 $this->logDeprecation('Checking property XMLParser::' . $name . ' is deprecated');
                 return isset($this->current_parsing_options['accept']);
+            case 'xmlrpc_valid_parents':
+                $this->logDeprecation('Checking property XMLParser::' . $name . ' is deprecated');
+                return isset($this->$name);
             default:
                 return false;
         }
@@ -1049,6 +1073,10 @@ class XMLParser
                 $this->logDeprecation('Unsetting property XMLParser::' . $name . ' is deprecated');
                 unset($this->current_parsing_options['accept']);
                 break;
+            case 'xmlrpc_valid_parents':
+                $this->logDeprecation('Unsetting property XMLParser::' . $name . ' is deprecated');
+                unset($this->$name);
+                break;
             default:
                 /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
                 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
index 0a5acf5..9a2757f 100644 (file)
@@ -259,7 +259,10 @@ class PhpXmlRpc
     {
         $reflection = new \ReflectionClass('PhpXmlRpc\PhpXmlRpc');
         foreach ($reflection->getStaticProperties() as $name => $value) {
-            $GLOBALS[$name] = $value;
+            if (!in_array($name, array('xmlrpc_return_datetimes', 'xmlrpc_reject_invalid_values', 'xmlrpc_datetime_format',
+                'xmlrpc_int_format', 'xmlrpc_double_format', 'xmlrpc_methodname_format', 'xmlrpc_silence_deprecations'))) {
+                $GLOBALS[$name] = $value;
+            }
         }
 
         // NB: all the variables exported into the global namespace below here do NOT guarantee 100% compatibility,
@@ -272,14 +275,10 @@ class PhpXmlRpc
             }
         }
 
+        /// @todo mke it possible to inject the XMLParser and Charset, as we do in other classes
+
         $parser = new Helper\XMLParser();
-        $reflection = new \ReflectionClass('PhpXmlRpc\Helper\XMLParser');
-        foreach ($reflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $name => $value) {
-            if (in_array($value->getName(), array('xmlrpc_valid_parents')))
-            {
-                $GLOBALS[$value->getName()] = $value->getValue($parser);
-            }
-        }
+        $GLOBALS['xmlrpc_valid_parents'] = $parser->xmlrpc_valid_parents;
 
         $charset = Charset::instance();
         $GLOBALS['xml_iso88591_Entities'] = $charset->getEntities('iso88591');
@@ -298,14 +297,19 @@ class PhpXmlRpc
      * @return void
      *
      * @deprecated
+     *
+     * @todo this function does not import back xmlrpc_valid_parents and xml_iso88591_Entities
      */
     public static function importGlobals()
     {
         $reflection = new \ReflectionClass('PhpXmlRpc\PhpXmlRpc');
-        $staticProperties = $reflection->getStaticProperties();
-        foreach ($staticProperties as $name => $value) {
-            if (isset($GLOBALS[$name])) {
-                self::$$name = $GLOBALS[$name];
+        foreach ($reflection->getStaticProperties() as $name => $value) {
+            if (!in_array($name, array('xmlrpc_return_datetimes', 'xmlrpc_reject_invalid_values', 'xmlrpc_datetime_format',
+                'xmlrpc_int_format', 'xmlrpc_double_format', 'xmlrpc_methodname_format', 'xmlrpc_silence_deprecations')))
+            {
+                if (isset($GLOBALS[$name])) {
+                    self::$$name = $GLOBALS[$name];
+                }
             }
         }
     }
index 2d9fd1f..c1248f8 100644 (file)
@@ -15,6 +15,12 @@ use PhpXmlRpc\Traits\PayloadBearer;
  * A client sends a PhpXmlrpc\Request to a server, and receives back an PhpXmlrpc\Response.
  *
  * @todo feature creep - add a protected $httpRequest member, in the same way the Response has one
+ *
+ * @property string $methodname deprecated - public access left in purely for BC. Access via method()/__construct()
+ * @property Value[] $params deprecated - public access left in purely for BC. Access via getParam()/__construct()
+ * @property int $debug deprecated - public access left in purely for BC. Access via .../setDebug()
+ * @property string $payload deprecated - public access left in purely for BC. Access via getPayload()/setPayload()
+ * @property string $content_type deprecated - public access left in purely for BC. Access via getContentType()/setPayload()
  */
 class Request
 {
@@ -23,16 +29,17 @@ class Request
     use ParserAware;
     use PayloadBearer;
 
-    /// @todo: do these need to be public?
-    /** @internal */
-    public $methodname;
-    /** @internal */
-    public $params = array();
+    /** @var string */
+    protected $methodname;
+    /** @var Value[] */
+    protected $params = array();
     /** @var int */
-    public $debug = 0;
+    protected $debug = 0;
 
-    // holds data while parsing the response. NB: Not a full Response object
-    /** @deprecated will be removed in a future release */
+    /**
+     * holds data while parsing the response. NB: Not a full Response object
+     * @deprecated will be removed in a future release
+     */
     protected $httpResponse = array();
 
     /**
@@ -413,4 +420,77 @@ class Request
         $this->debug = $level;
         return $this;
     }
+
+    // *** BC layer ***
+
+    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
+    public function &__get($name)
+    {
+        switch ($name) {
+            case 'me':
+            case 'mytype':
+            case '_php_class':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Getting property Request::' . $name . ' is deprecated');
+                return $this->$name;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+                $result = null;
+                return $result;
+        }
+    }
+
+    public function __set($name, $value)
+    {
+        switch ($name) {
+            case 'methodname':
+            case 'params':
+            case 'debug':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Setting property Request::' . $name . ' is deprecated');
+                $this->$name = $value;
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
+
+    public function __isset($name)
+    {
+        switch ($name) {
+            case 'methodname':
+            case 'params':
+            case 'debug':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Checking property Request::' . $name . ' is deprecated');
+                return isset($this->$name);
+            default:
+                return false;
+        }
+    }
+
+    public function __unset($name)
+    {
+        switch ($name) {
+            case 'methodname':
+            case 'params':
+            case 'debug':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Unsetting property Request::' . $name . ' is deprecated');
+                unset($this->$name);
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
 }
index 64e6373..d822d3c 100644 (file)
@@ -12,9 +12,15 @@ use PhpXmlRpc\Traits\PayloadBearer;
  * Server-side, a server method handler will construct a Response and pass it as its return value.
  * An identical Response object will be returned by the result of an invocation of the send() method of the Client class.
  *
- * @property array $hdrs deprecated, use $httpResponse['headers']
- * @property array _cookies deprecated, use $httpResponse['cookies']
- * @property string $raw_data deprecated, use $httpResponse['raw_data']
+ * @property Value|string|mixed $val deprecated - public access left in purely for BC. Access via value()/__construct()
+ * @property string $valtyp deprecated - public access left in purely for BC. Access via valueType()/__construct()
+ * @property int $errno deprecated - public access left in purely for BC. Access via faultCode()/__construct()
+ * @property string $errstr deprecated - public access left in purely for BC. Access faultString()/__construct()
+ * @property string $payload deprecated - public access left in purely for BC. Access via getPayload()/setPayload()
+ * @property string $content_type deprecated - public access left in purely for BC. Access via getContentType()/setPayload()
+ * @property array $hdrs deprecated. Access via httpResponse()['headers'], set via $httpResponse['headers']
+ * @property array _cookies deprecated. Access via httpResponse()['cookies'], set via $httpResponse['cookies']
+ * @property string $raw_data deprecated. Access via httpResponse()['raw_data'], set via $httpResponse['raw_data']
  */
 class Response
 {
@@ -22,15 +28,14 @@ class Response
     use DeprecationLogger;
     use PayloadBearer;
 
-    /// @todo: do these need to be public?
-    /** @internal */
-    public $val = 0;
-    /** @internal */
-    public $valtyp;
-    /** @internal */
-    public $errno = 0;
-    /** @internal */
-    public $errstr = '';
+    /** @var Value|string|mixed */
+    protected $val = 0;
+    /** @var string */
+    protected $valtyp;
+    /** @var int */
+    protected $errno = 0;
+    /** @var string */
+    protected $errstr = '';
 
     protected $httpResponse = array('headers' => array(), 'cookies' => array(), 'raw_data' => '', 'status_code' => null);
 
@@ -218,6 +223,14 @@ class Response
     public function &__get($name)
     {
         switch ($name) {
+            case 'val':
+            case 'valtyp':
+            case 'errno':
+            case 'errstr':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
+                return $this->$name;
             case 'hdrs':
                 $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
                 return $this->httpResponse['headers'];
@@ -239,6 +252,15 @@ class Response
     public function __set($name, $value)
     {
         switch ($name) {
+            case 'val':
+            case 'valtyp':
+            case 'errno':
+            case 'errstr':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
+                $this->$name = $value;
+                break;
             case 'hdrs':
                 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
                 $this->httpResponse['headers'] = $value;
@@ -261,6 +283,14 @@ class Response
     public function __isset($name)
     {
         switch ($name) {
+            case 'val':
+            case 'valtyp':
+            case 'errno':
+            case 'errstr':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
+                return isset($this->$name);
             case 'hdrs':
                 $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
                 return isset($this->httpResponse['headers']);
@@ -278,6 +308,15 @@ class Response
     public function __unset($name)
     {
         switch ($name) {
+            case 'val':
+            case 'valtyp':
+            case 'errno':
+            case 'errstr':
+            case 'payload':
+            case 'content_type':
+                $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
+                unset($this->$name);
+                break;
             case 'hdrs':
                 $this->logDeprecation('Unsetting property Response::' . $name . ' is deprecated');
                 unset($this->httpResponse['headers']);
index 0915e45..a41cc36 100644 (file)
@@ -14,6 +14,15 @@ use PhpXmlRpc\Traits\ParserAware;
 
 /**
  * Allows effortless implementation of XML-RPC servers
+ *
+ * @property string[] $accepted_compression deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property bool $allow_system_funcs deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property bool $compress_response deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property int $debug deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property int $exception_handling deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property string $functions_parameters_type deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property array $phpvals_encoding_options deprecated - public access left in purely for BC. Access via getOption()/setOption()
+ * @property string $response_charset_encoding deprecated - public access left in purely for BC. Access via getOption()/setOption()
  */
 class Server
 {
@@ -37,7 +46,7 @@ class Server
      *
      * @todo create class constants for these
      */
-    public $functions_parameters_type = 'xmlrpcvals';
+    protected $functions_parameters_type = 'xmlrpcvals';
 
     /**
      * @var array
@@ -45,7 +54,7 @@ class Server
      * when the functions_parameters_type member is set to 'phpvals'.
      * @see Encoder::encode for a list of values
      */
-    public $phpvals_encoding_options = array('auto_dates');
+    protected $phpvals_encoding_options = array('auto_dates');
 
     /**
      * @var int
@@ -57,7 +66,7 @@ class Server
      * 2 =
      * 3 =
      */
-    public $debug = 1;
+    protected $debug = 1;
 
     /**
      * @var int
@@ -68,7 +77,7 @@ class Server
      * 2 = allow the exception to float to the upper layers
      * Can be overridden per-method-handler in the dispatch map
      */
-    public $exception_handling = 0;
+    protected $exception_handling = 0;
 
     /**
      * @var bool
@@ -76,27 +85,27 @@ class Server
      * for compression in the request.
      * Automatically set at constructor time.
      */
-    public $compress_response = false;
+    protected $compress_response = false;
 
     /**
      * @var string[]
      * List of http compression methods accepted by the server for requests. Automatically set at constructor time.
      * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
      */
-    public $accepted_compression = array();
+    protected $accepted_compression = array();
 
     /**
      * @var bool
      * Shall we serve calls to system.* methods?
      */
-    public $allow_system_funcs = true;
+    protected $allow_system_funcs = true;
 
     /**
      * List of charset encodings natively accepted for requests.
      * Set at constructor time.
-     * UNUSED so far...
+     * @deprecated UNUSED so far...
      */
-    public $accepted_charset_encodings = array();
+    protected $accepted_charset_encodings = array();
 
     /**
      * @var string
@@ -108,7 +117,18 @@ class Server
      * - 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway).
      * NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
      */
-    public $response_charset_encoding = '';
+    protected $response_charset_encoding = '';
+
+    protected static $options = array(
+        self::OPT_ACCEPTED_COMPRESSION,
+        self::OPT_ALLOW_SYSTEM_FUNCS,
+        self::OPT_COMPRESS_RESPONSE,
+        self::OPT_DEBUG,
+        self::OPT_EXCEPTION_HANDLING,
+        self::OPT_FUNCTIONS_PARAMETERS_TYPE,
+        self::OPT_PHPVALS_ENCODING_OPTIONS,
+        self::OPT_RESPONSE_CHARSET_ENCODING,
+    );
 
     /**
      * @var mixed
@@ -123,17 +143,6 @@ class Server
      */
     protected $dmap = array();
 
-    protected $options = array(
-        self::OPT_ACCEPTED_COMPRESSION,
-        self::OPT_ALLOW_SYSTEM_FUNCS,
-        self::OPT_COMPRESS_RESPONSE,
-        self::OPT_DEBUG,
-        self::OPT_EXCEPTION_HANDLING,
-        self::OPT_FUNCTIONS_PARAMETERS_TYPE,
-        self::OPT_PHPVALS_ENCODING_OPTIONS,
-        self::OPT_RESPONSE_CHARSET_ENCODING,
-    );
-
     /**
      * Storage for internal debug info.
      */
@@ -194,28 +203,14 @@ class Server
     {
         switch ($name) {
             case self::OPT_ACCEPTED_COMPRESSION :
-                $this->accepted_charset_encodings = $value;
-                break;
             case self::OPT_ALLOW_SYSTEM_FUNCS:
-                $this->allow_system_funcs = $value;
-                break;
             case self::OPT_COMPRESS_RESPONSE:
-                $this->compress_response = $value;
-                break;
             case self::OPT_DEBUG:
-                $this->debug = $value;
-                break;
             case self::OPT_EXCEPTION_HANDLING:
-                $this->exception_handling = $value;
-                break;
             case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
-                $this->functions_parameters_type = $value;
-                break;
             case self::OPT_PHPVALS_ENCODING_OPTIONS:
-                $this->phpvals_encoding_options = $value;
-                break;
             case self::OPT_RESPONSE_CHARSET_ENCODING:
-                $this->response_charset_encoding = $value;
+                $this->$name = $value;
                 break;
             default:
                 throw new ValueErrorException("Unsupported option '$name'");
@@ -233,21 +228,14 @@ class Server
     {
         switch ($name) {
             case self::OPT_ACCEPTED_COMPRESSION:
-                return $this->accepted_compression;
             case self::OPT_ALLOW_SYSTEM_FUNCS:
-                return $this->allow_system_funcs;
             case self::OPT_COMPRESS_RESPONSE:
-                return $this->compress_response;
             case self::OPT_DEBUG:
-                return $this->debug;
             case self::OPT_EXCEPTION_HANDLING:
-                return $this->exception_handling;
             case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
-                return $this->functions_parameters_type;
             case self::OPT_PHPVALS_ENCODING_OPTIONS:
-                return $this->phpvals_encoding_options;
             case self::OPT_RESPONSE_CHARSET_ENCODING:
-                return $this->response_charset_encoding;
+                return $this->$name;
             default:
                 throw new ValueErrorException("Unsupported option '$name'");
         }
@@ -260,7 +248,7 @@ class Server
     public function getOptions()
     {
         $values = array();
-        foreach($this->options as $opt) {
+        foreach(static::$options as $opt) {
             $values[$opt] = $this->getOption($opt);
         }
         return $values;
@@ -1442,4 +1430,87 @@ class Server
             return "<?xml version=\"1.0\"?" . ">\n";
         }
     }
+
+    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
+    public function &__get($name)
+    {
+        switch ($name) {
+            case self::OPT_ACCEPTED_COMPRESSION :
+            case self::OPT_ALLOW_SYSTEM_FUNCS:
+            case self::OPT_COMPRESS_RESPONSE:
+            case self::OPT_DEBUG:
+            case self::OPT_EXCEPTION_HANDLING:
+            case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
+            case self::OPT_PHPVALS_ENCODING_OPTIONS:
+            case self::OPT_RESPONSE_CHARSET_ENCODING:
+                $this->logDeprecation('Getting property Request::' . $name . ' is deprecated');
+                return $this->$name;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+                $result = null;
+                return $result;
+        }
+    }
+
+    public function __set($name, $value)
+    {
+        switch ($name) {
+            case self::OPT_ACCEPTED_COMPRESSION :
+            case self::OPT_ALLOW_SYSTEM_FUNCS:
+            case self::OPT_COMPRESS_RESPONSE:
+            case self::OPT_DEBUG:
+            case self::OPT_EXCEPTION_HANDLING:
+            case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
+            case self::OPT_PHPVALS_ENCODING_OPTIONS:
+            case self::OPT_RESPONSE_CHARSET_ENCODING:
+                $this->logDeprecation('Setting property Request::' . $name . ' is deprecated');
+                $this->$name = $value;
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
+
+    public function __isset($name)
+    {
+        switch ($name) {
+            case self::OPT_ACCEPTED_COMPRESSION :
+            case self::OPT_ALLOW_SYSTEM_FUNCS:
+            case self::OPT_COMPRESS_RESPONSE:
+            case self::OPT_DEBUG:
+            case self::OPT_EXCEPTION_HANDLING:
+            case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
+            case self::OPT_PHPVALS_ENCODING_OPTIONS:
+            case self::OPT_RESPONSE_CHARSET_ENCODING:
+                $this->logDeprecation('Checking property Request::' . $name . ' is deprecated');
+                return isset($this->$name);
+            default:
+                return false;
+        }
+    }
+
+    public function __unset($name)
+    {
+        switch ($name) {
+            case self::OPT_ACCEPTED_COMPRESSION :
+            case self::OPT_ALLOW_SYSTEM_FUNCS:
+            case self::OPT_COMPRESS_RESPONSE:
+            case self::OPT_DEBUG:
+            case self::OPT_EXCEPTION_HANDLING:
+            case self::OPT_FUNCTIONS_PARAMETERS_TYPE:
+            case self::OPT_PHPVALS_ENCODING_OPTIONS:
+            case self::OPT_RESPONSE_CHARSET_ENCODING:
+                $this->logDeprecation('Unsetting property Request::' . $name . ' is deprecated');
+                unset($this->$name);
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
 }
index 877009f..026130d 100644 (file)
@@ -5,9 +5,9 @@ namespace PhpXmlRpc\Traits;
 trait PayloadBearer
 {
     /** @var string */
-    public $payload;
+    protected $payload;
     /** @var string */
-    public $content_type = 'text/xml';
+    protected $content_type = 'text/xml';
 
     /**
      * @internal
index 30a9c6b..64a9dbe 100644 (file)
@@ -10,6 +10,10 @@ use PhpXmlRpc\Traits\DeprecationLogger;
 
 /**
  * This class enables the creation of values for XML-RPC, by encapsulating plain php values.
+ *
+ * @property Value[]|mixed $me deprecated - public access left in purely for BC. Access via scalarVal()/__construct()
+ * @property int $params $mytype - public access left in purely for BC. Access via kindOf()/__construct()
+ * @property string|null $_php_class deprecated - public access left in purely for BC.
  */
 class Value implements \Countable, \IteratorAggregate, \ArrayAccess
 {
@@ -43,16 +47,14 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess
         "null" => 1,
     );
 
-    /// @todo: do these need to be public?
     /** @var Value[]|mixed */
-    public $me = array();
+    protected $me = array();
     /**
      * @var int 0 for undef, 1 for scalar, 2 for array, 3 for struct
-     * @internal
      */
-    public $mytype = 0;
+    protected $mytype = 0;
     /** @var string|null */
-    public $_php_class = null;
+    protected $_php_class = null;
 
     /**
      * Build an xml-rpc value.
@@ -675,4 +677,67 @@ class Value implements \Countable, \IteratorAggregate, \ArrayAccess
 
         return count($this->me['struct']);
     }
+
+    // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
+    public function &__get($name)
+    {
+        switch ($name) {
+            case 'me':
+            case 'mytype':
+            case '_php_class':
+                $this->logDeprecation('Getting property Value::' . $name . ' is deprecated');
+                return $this->$name;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+                $result = null;
+                return $result;
+        }
+    }
+
+    public function __set($name, $value)
+    {
+        switch ($name) {
+            case 'me':
+            case 'mytype':
+            case '_php_class':
+                $this->logDeprecation('Setting property Value::' . $name . ' is deprecated');
+                $this->$name = $value;
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
+
+    public function __isset($name)
+    {
+        switch ($name) {
+            case 'me':
+            case 'mytype':
+            case '_php_class':
+                $this->logDeprecation('Checking property Value::' . $name . ' is deprecated');
+                return isset($this->$name);
+            default:
+                return false;
+        }
+    }
+
+    public function __unset($name)
+    {
+        switch ($name) {
+            case 'me':
+            case 'mytype':
+            case '_php_class':
+                $this->logDeprecation('Unsetting property Value::' . $name . ' is deprecated');
+                unset($this->$name);
+                break;
+            default:
+                /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
+                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
+                trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING);
+        }
+    }
 }