From SimpleXMLElement to SimpleXMLIterator - php

I have a nice function that converts a (simple, duh) xml to an array, and to do so it uses the SimpleXmlIterator class.
It works quite well, but I'd like to make it accept not only xml source strings or SimpleXmlIterator objects, but SimpleXmlElements too since I use them way more often that iterators (that I use just in that function, actually).
What I did so far was
$iter = new SimpleXmlIterator($xml->asXML());
but to me it's like passing through Tokyo to get from Paris to London. After all, SimpleXmlIterator extends SimpleXmlElement, so is there a better way to convert a SimpleXmlElement object to a SimpleXmlIterator?

You can use SimpleXMLIterator at the beginning by setting the second parameter in http://php.net/manual/de/function.simplexml-load-file.php
$yourSimpleXMLIteratorObject = simplexml_load_file("your_file.xml","SimpleXMLIterator");
all Objects resulting, are now SimpleXMLIterator-Objects

Why not parse all your XML into SimpleXMLIterator objects to begin with if you plan to use them as such?
As far as I know there is not an easy way to convert/cast from SimpleXMLElement to SimpleXMLIterator. These classes simply wrap a libxml resource so you would think there would be a way to obtain a resource handle and pass it into SimpleXML* constructors, but if there is it's news to me.

Related

PHP: is this a bug: shuffle() expects parameter 1 to be array, object given?

I have an object that implements the ArrayableInterface (BTW, it's from Laravel's Eloquent ORM).
This object is $articles. So naturally, I can do this:
foreach ($articles as $article)
echo $article->title . "<br/>";
But I can't do this:
shuffle($articles);
I get the shuffle() expects parameter 1 to be array, object given warning.
No, it's not a bug.
PHP 5 allows you to use foreach() to loop through objects that aren't arrays. These objects are called Iterators.
Unfortunately, the old array-based functions, like shuffle() cannot process Iterators.
The main reason for this is that an Iterator may not even be sortable -- for example, you can have iterators that read directly from a file or a URL, and read a new line of data each time the foreach() loop cycles. This clearly can't be sorted because it's read during the foreach() process.
You can convert an Iterator into an array, using the cleverly named iterator_to_array() function. However, this may be a bad idea if you don't know how much data the iterator is going to process, as you may find it uses a lot of memory.
Some iterators may provide methods within the iterator object itself for sorting or filtering the data. If so, this is a better solution than trying to sort it as an array.
If you're working with an ORM, then this implies that your Iterator object is reading data from a DB. In this case, sorting it via the DB query (ie ORDER BY or whatever methods the ORM provides to do that) would probably be a better solution than sorting the data in PHP.
I don't know what the interface does.. but nor will the shuffle function because it only recognises arrays. You'd need to do this:
$array = iterator_to_array($articles);
$shuffled = shuffle($array);
From an OOP perspective, really, your object should contain the shuffle implementation:
$articles->shuffle();

PHP XML performance and serialize()

I have an XML file which contains the structure of some objects. The object is like this:
class Object:
{
private $name;
private $info;
private $$items;
}
Where $items is an array of objects, so it is recursive.
As of now, when I have to list the items I use simplexml to iterate within the elements and show them.
My questions are:
1) If I parse the XML and convert the data into the object instead of working with pure XML, would it affect the overall performance of the pages all that much? Will it slow down too much considering that every page the user loads he will have to load the items?
2) Is it a good idea to serialize() a recursive object like the one I’ve defined?
SimpleXML cannot be serialized because it's considered to be a resource. However, you can easily grab the output of $sx->toXML(); and serialize that, re-constructing the SimpleXMLElement(s) once you've unserialized them.
The performance difference of re-parsing the XML is not very considerable unless you're working with extremely large XML trees.
In regards to your object, you can also implement the __sleep() and __wakeup() magic methods that will allow you do alter the object before it is serialized and unserialized respectively.
When serializing your recursive object example, don't include your $$items variable in the __sleep() magic method and re-implement it in __wakeup.

which is better expression to make string into xml object[php]?

which is better expression to make string into xml object[php]?
$xml = new SimpleXMLElement($xml_string);
vs
$xml = simplexml_load_string($xml_string);
same?
They're basically identical. SimpleXMLElement::__construct accepts data strings or file paths, if you set the appropriate options. simplexml_load_file and simplexml_load_string are basically convenience function wrappers that amount to the same thing as new SimpleXMLElement() with the correct options set.
They're essentially the same. Which one you use is based on personal taste. I'd go for the first. The simplexml_load_string function will create an object too, which makes it essentially an alias for the constructor.
The simplexml_load_string lets you specify the class of which you want to get the object of. If you call the simplexml_load_string without specifying the class as second parameter, then it automatically gives you the object of SimpleXMLElement.
So, in the way you are running it, they both will give you same results.

simplexml get node value without typecasting

Is there any way to get a node value from a simplexml object without casting it?
$amount = (int)$item->amount;
This is not very beautiful in my opinion, I'm searching for a cleaner way but did not find anything so far!
//wouldn't this be nice?
$amount = $item->amount->getValue();
Thanks in advance.
No. SimpleXml only exposes a very limited API to work with nodes. It's implicit API is considered a feature. If you need more control over the nodes, use DOM:
$sxe = simplexml_load_string(
'<root><item><amount>10</amount></item></root>'
);
$node = dom_import_simplexml($sxe->item->amount);
var_dump($node->nodeValue); // string(2) "10"
The dom_import_simplexml function will convert the node from a SimpleXmlElement to a DOMElement, so you are still casting behind the scenes somehow. You no longer need to typecast explicitly though, when fetching the content from the DOMElement.
On a sidenote: personally, I find DOM superior to SimpleXml and I'd suggest not to use SimpleXml but DOM right away. If you want to familiarize yourself with it, have a look at some of my previous answers about using DOM.
Getting the value of a node without having to typecast it? Sure thing! :3
class SimplerXMLElement extends SimpleXMLElement
{
public function getValue()
{
return (string) $this;
}
}
Now you just have to use simplexml_load_string()'s second parameter to get even simpler XML elements!
More seriously though, a node is a node. If you need to use the value of a node as a string, integer and what not, it will involve typecasting at one point or another, whether you do it personally or not.
But it is the safest :). You could create a function to recursively convert the object in an array. Way back when I first starte working with XML in PHP, I remember reaching the conclusion that type casting is just the best method :)
What about xpath way?
$amount = $item->amount->xpath('text()');

Why It is not possible to serialize PHP built-in objects?

I have tried to unserialize a PHP Object.
Warning: unserialize() [function.unserialize]: Node no longer exists in /var/www/app.php on line 42
But why was that happen?
Even if I found a solution to unserialize simplexml objects, its good to know why php cant unserialize objects?
To serialize simplexml object i use this function
function serializeSimpleXML(SimpleXMLElement $xmlObj)
{
return serialize($xmlObj->asXML());
}
To unserialize an simplexml objetc i use this function
function unserializeSimpleXML($str)
{
return simplexml_load_string(unserialize($str));
}
SimpleXMLElement wraps a libxml resource type. Resources cannot be serialized. On the next invocation, the resource representing the libxml Node object doesn't exist, so unserialization fails. It may be a bug that you are allowed to serialize a SimpleXMLElement at all.
Your solution is the correct one, since text/xml is the correct serialization format for anything XML. However, since it is just a string, there isn't really any reason to serialize the XML string itself.
Note that this has nothing inherently to do with "built-in" PHP classes/objects, but is an implementation detail of SimpleXML (and I think DOM in PHP 5).
just inherent the class(the main xml class would be best) in a other one
and use __sleep
to store the data required to initialize simplexml(any object)
and __wake
to reinitialize the object as required
this way you can serialize(any object)
edit: remember this class needs to be accessible first,
this can be done by loading(including) the class or an __autoload

Categories