Re: [PEPr] -1 for XML::XML_RPC2
| From: | Sergio Carvalho | Date: | Sat, 14 May 2005 18:54:38 +0000 |
| Subject: | Re: [PEPr] -1 for XML::XML_RPC2 | ||
| References: | 1 2 3 4 5 6 7 8 9 10 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-37628@lists.php.net to get a copy of this message | ||
Hi,
Greg Beaver wrote:
> This is still completely unnecessary :)
>
> $proxy->foo((object) array('bar', 'baz'))
>
> will automatically send a struct instead of an array, as objects are
> auto-converted to structs.
We usually call that here a "kick in the code". You are using a side
effect as a feature. It's a kick because it's the same method you use to
get older equipment working -- rusting refrigerators, TVs, etc :-).
BTW, on XML_RPC2, objects are serialized and sent as base64 strings. It
just shows how unobvious the behaviour is.
> The *only* instance where it is absolutely necessary to use an object is
> for base64 and datetime.
It's still enough for type handling to be a designed feature of the package.
> Incidentally, it is also perfectly possible to use the above syntax in
> my implementation if the user does not prefer to use setType(), and
> never wishes to use the xmlrpc-epi extension, I'll show below. Your
> design, however, makes using an xmlrpc-epi backend much more complex
> than using the php backend internally.
Internally, it's just slightly more complicated, as I'll point out
below. Externally, it's not different. For the end user, which backed is
used is transparent.
> This strays from the main point: none of the complex classes are
> necessary to create a clear structure. Let me put it this way: which is
> going to be easier to work with inside the XML_RPC2 class/cleare to the
> end user?
>
> #1
> <?php
> $xmlrpc->someFunction(array(
> 'hi' => (object) array(1,2.0,3),
> 'time' => array('hours' => 12, 'minutes' => 30),
> 'binarydata' => new Chiara_XML_RPC5_Custom($data, 'base64')));
> // or
> $data = array(
> 'hi' => (object) array(1,2,3),
> 'time' => array('hours' => 12, 'minutes' => 30),
> 'binarydata' => $data);
> $xmlrpc->setType($data['binarydata'], 'base64');
> $someFunction($data);
> ?>
>
> <?php
> $xmlrpc->someFunction(new XML_RPC2_Value_Struct(
> array(
> 'hi' => new XML_RPC2_Value_Struct(array(new XML_RPC2_Value_Int(1),
> new XML_RPC2_Value_Double(2.0),new XML_RPC2_Value_Int(3))),
> 'time' => new XML_RPC2_Value_Struct(array('hours' => new
> XML_RPC2_Value_Int(12), 'minutes' => new XML_RPC2_Value_Int(30))),
> 'binarydata' => new XML_RPC2_Value_Base64($data))));
> ?>
This is unfair. The external interface would never look like this. It's
more like:
<?php
$xmlrpc->someFunction(
array(
'hi' => new XML_RPC2_Value_Struct(array(1, 2.0, 3)),
'time' => array('hours' => 12, 'minutes' => 30),
'binarydata' => new XML_RPC2_Value_Base64($data)
));
?>
which is, if you look at it, much much clearer than the setType version,
which is separating data from its type. Here, the explicit type is set
along with the data.
>
> Now I realize the user probably would never do this, but your code
> converts the native PHP types into this exact structure.
>
> If used with an xmlrpc-epi backend, the second choice will have double
> conversion - the user would create the complex object, and then the
> backend would have to just convert it back into the native PHP types and
> use settype() on the base64.
You realize the complex object has the same weight of a struct like this
one:
array('_val' => array(1, 2.0, 3))
since PHP objects are glorified arrays with added type information.
> It's just bad design to do this, forget OO/procedural. By using these
> custom type classes for every single XML-RPC value, you are introducing
> an extreme element of inflexibility, a performance hit, and coding
> complexity.
- Inflexibility: Why? Please ellaborate. I can only see reasons why it
is *more* flexible, not less.
- Performance hit: I've proved it didn't affect performance. Get some
numbers like I did.
- Coding complexity: Which one is more complex? This:
<?php
$xmlrpc->someFunction(
array(
'hi' => new XML_RPC2_Value_Struct(array(1, 2.0, 3)),
'time' => array('hours' => 12, 'minutes' => 30),
'binarydata' => new XML_RPC2_Value_Base64($data)
));
?>
or this:
<?php
$data = array(
'hi' => array(1,2,3),
'time' => array('hours' => 12, 'minutes' => 30),
'binarydata' => $data);
$xmlrpc->setType($data['hi'], 'struct');
$xmlrpc->setType($data['binarydata'], 'base64');
$someFunction($data);
?>
>> I realize the extensions do this using setType. That approach strikes me
>> as smelly. Why represent the concept of type using a band aid when the
>> language provides me with a native form of representing types?
>
> I have no problem with providing a custom object for datetime and base64
> - This will work just fine and is necessary to work with non-extension
> based drivers.
>
>>> <?php
>>> $xmlrpc = new
>>> Chiara_XML_RPC5('http://example.com/xmlrpc.php');
>>> $arr = array(1,2,'base64');
>>> $xmlrpc->setType($arr[2], 'base64');
>>> $result = $xmlrpc->someFunction($arr);
>>> ?>
>>
>>
>>
>> Isn't it much cleaner to do:
>>
>> <?php
>> $xmlrpc = new
>> XML_RPC2_Server('http://example.com/xmlrpc.php');
>> $xmlrpc->someFunction(1,2, new XML_RPC_Value_Base64('base64'));
>> ?>
>
>
> Perhaps it appears so on the surface - but the xmlrpc-epi driver would
> then be forced to iterate over the entire data structure looking for
> these classes, and convert them back to the original native PHP type and
> run settype() on them internally. The only driver that would benefit
> from this approach is the PHP-based driver, and the benefits are
> negligible.
>
> However, I *could* see this working as an option:
>
> $xmlrpc->someFunction(1,2, $xmlrpc->retrieveType($stuff, 'base64'));
>
> This would allow the driver to return the appropriate type, so that a
> php-based driver would return an object, and the xmlrpc-epi driver would
> return a native php value that was settype()d.
We might have some common ground here. Why not a static factory of the
XML_RPC_Value object:
$xmlrpc->someFunction(1,2, XML_RPC2_Value_Base64::construct($stuff));
Where 'construct' behaviour could be backend-dependant. xmlrpc-epi just
returns $stuff settype()d and the PHP backend returns the encoded object?
> The ->retrieveType() example is probably what you might consider to be
> procedural because it uses a method to retrieve the actual value used,
> but it is really better OO encapsulation in disguise. By hiding the
> implementation from the user, you provide a *much* better system for
> internal implementation, without confusing the user at all. In
> addition, it uses the principal of API interface as the php, xmlrpc-epi,
> and xmlrpci drivers would simply have the same method, and all three
> could be swapped out without a single change to the code.
Both solutions attack the same problem (mapping php types to xmlrpc),
and they both expose the same level of internals to the user. One is
procedural (using strings to define types) while the other is OO (using
classes to define types). How you can think that setType better hides
the internals is beyond me.
> Now, to be fair, Chiara_XML_RPC5 does not have any kind of
> retrieveType() method. This goes with my other point: if we had this
> argument offlist BEFORE you brought the thing to a vote, perhaps we
> could have worked out the differences. The spirit of collaboration
> (which includes debates over implementation like this) lead to better
> coding solutions, I am convinced of that.
We had, six months ago, and none of this was raised then.
If you wish, contact me offlist (ICQ#67512780), 14h00-20h00 GMT. It
might be faster and less noisy to agree on a design offlist.
Cheers,
--
Sérgio Carvalho