XML and JSON

Last updated Mar 23, 2024 Published Mar 20, 2018

The content here is under the Attribution 4.0 International (CC BY 4.0) license

PHP was born out of the need to have an easier way to develop web applications. Today, it supports HTML, XML and JSON, and has specific functions for their use. For the certification test, we must be familiar with handling these types of data. In this chapter, we will learn about the functions provided by PHP for manipulation and validation.

In fact, the test requires good knowledge and mastery of these technologies, so I recommend, before continuing reading, that you review the concepts that cover HTML, XML and JSON. If you already feel familiar with these technologies, go ahead. Here we seek to expose the maximum of what PHP offers us to work with through APIs that have existed since version 5.0 of PHP.

simplexml_*, SimpleXMLElement

With PHP, we have some options for manipulating XML, such as simplexml_*. This type of use is more focused on practicality in previous versions of PHP 5.2, and in other versions that did not have a strong object-oriented culture. For the functions below, PHP uses an extension called libxml, to provide some XML-related functionality.

$myXML = '<root/>';
simplexml_load_string($myXML);

In this example, we have the simplest way to use the function, passing only the string containing valid XML. However, we have several other arguments to use this function, such as passing the name of the class that we want the function to return as an object to us.

$myXML = '<root/>';
simplexml_load_string($myXML, 'SimpleXMLElement');

This makes XML management very flexible as we can write our own class and use it.

class MySimpleXml extends SimpleXMLElement {}

$myXML = '<root/>';

simplexml_load_string($myXML, 'MySimpleXml');

As a third parameter to the simplexml_load_string function, we can pass constants directly related to the libxml extension, for example, the constant LIBXML_NOERROR, which suppresses (i.e. “hides”) errors during the process.

For a list of all available constants, see the official PHP manual, at http://php.net/manual/libxml.constants.php.

simplexml_load_string($myXML, 'SimpleXMLElement', LIBXML_NOERROR);

Using namespaces with XML is very common as well, and simplexml_load_string gives us a very easy way to use nodes from a given namespace.

simplexml_load_string($myXML, 'SimpleXMLElement', LIBXML_NOERROR, 'namespace');

Lastly, we have the parameter to inform whether there is a prefix or not.

Now that we know how to use the simplexml_load_string function, it is possible to apply the same knowledge to the simplexml_load_file function, as all parameters of the simplexml_load_string function are valid for it. The only difference we should keep in mind is that, with simplexml_load_file, we inform the path of a file and, with simplexml_load_string, we inform a string containing the XML.

Using the SimpleXMLElement class, we can represent one or several elements existing in an XML document.

$myXml = <<<XMLDATA
<zce>
    <basic>
        <syntax>
        PHP tags, Bitwise
        </syntax>
    </basic>
</zce>
XMLDATA;

SimpleXMLElement provides us with a very easy way to access XML elements as if they were objects.

$myXml = new SimpleXMLElement($myXml);
$myXml->basic; //will return a SimpleXMLElement object

Or we can use the methods provided by the class to access its nodes.

$myXml = new SimpleXMLElement($myXml);
$myXml->children(); //will return a SimpleXMLElement object

An interesting point to note when accessing elements is that we do not need to reference the root node of the XML document, which in our case is zce. This way, it is easy to access its child nodes directly, as shown in the example.

PHP provides much more than these classes for manipulating XML, for example, using a SimpleXMLIterator to iterate over all nodes in your XML, a parser to define different types of manipulations for different events, among others. For a complete list of what PHP provides for XML manipulation, use the official documentation at http://php.net/manual/en/refs.xml.php.

DOM (Document Object Model)

PHP offers us an option to manipulate XML through the DOM API. DOM (Document Object Model) is an interface for XML, HTML and also SVG documents. This API provides us with a representation of the document structure, and also defines how this structure can be manipulated. Just like SimpleXMLELement, the DOM API provides us with a representation of the document through objects. Web programmers are very familiar with it, as JavaScript, for example, uses this representation to access the elements of an HTML page.

In PHP, the DOM API provides us with several classes to use. To check all the existing details, check the official documentation at http://php.net/manual/en/book.dom.php.

The main class we’re going to pay attention to now is DOMDocument, which actually represents an entire XML document. We can use it in different ways, such as reading an XML file from a certain directory:

$load = new DOMDocument();
$load->load('/path/to/file/my.xml');

Or loading information from text with HTML formatting:

$loadHtml = new DOMDocument();
$loadHtml->loadHTML('<html><p>Hello</p><br></html>');

Even load data from an HTML file:

$loadHtmlFile = new DOMDocument();
$loadHtmlFile->loadHTMLFile('/path/to/file/my.html');

Or, in the most basic way, through plain XML text:

$loadString = new DOMDocument();
$loadString->loadXML('<root><name>PHP</name></root>);

Combining DOMDocument and SimpleXMLElement

PHP provides us with countless possibilities when working with XML, including the fact that we can convert a SimpleXMLElement object to a DOMNode, or vice versa.

$no = new DOMDocument();
$no->loadXML('<root></root>');

simplexml_import_dom($no);

We have the possibility of informing the class to which the object will be converted, which gives us a lot of flexibility to create our own class to use with SimpleXMLElement.

class MyElement extends SimpleXMLElement {}

$no = new DOMDocument();
$no->loadXML('<root/>');

simplexml_import_dom($no, 'MyElement');

And we can convert a DOMNode to a SimpleXMLElement.

$no = new SimpleXMLElement('<root/>');

dom_import_simplexml($no);

xpath and DOMDocument

xpath provides us with an elegant way to find nodes in an XML document, through patterns. These patterns look like a URL. See our first example:

$xml = '
<library>
    <book id="1">
        <name>PHP</name>
        <description>Learn PHP</description>
    </book>
</library>
';

$document = new DOMDocument();
$document->loadXML($xml);

$xpath = new DOMXpath($document);
$element = $xpath->query('/library/book');

print_r($element);

In this example we are searching for all nodes (with the name book) existing in the XML, starting from the root node library, in this case we will find only one element:

DOMNodeList Object
(
    [length] => 1
)

As we are using xpath through DOMDocument, a list of nodes (DOMNodeList) is returned so that we can iterate through the objects found. So you can display the node list any way you want:

foreach ($elements as $no) {
    print $no->nodeValue;
}

As we are taking each book node in the document, using the nodeValue attribute on each node, we display the contents of all its child elements:

PHP // name
Learn PHP //description

But you must be wondering how you use the query method to find different nodes in your XML document. To get started, see the table below, which has the basics for navigating your document through xpath.

Element Description
/ Starts the search from the root node
// Search for the desired element, no matter where it is
@ Used to find attributes

Let’s change our example now so that it finds books nodes anywhere in our document:

$xml = '
<library>
    <shelf identifier="C2">
        <book id="1">
            <name>PHP</name>
            <description>Learn PHP</description>
        </book>
        <book id="2">
            <name>Zend framework</name>
            <description>How to use the Zend framework</description>
        </book>
    </shelf>
    <shelf identifier="D1">
        <book id="5">
            <name>Bitwise</name>
            <description>Bitwise manipulation for ninjas</description>
        </book>
    </shelf>
</library>
';

$document = new DOMDocument();
$document->loadXML($xml);

$xpath = new DOMXpath($document);
$element = $xpath->query('//book');

print_r($element);

As we are only looking for the book node regardless of where it is, we obtain 3 elements. See our DOMNodeList object:

DOMNodeList Object
(
    [length] => 3
)

What if we only want the books on shelf D1? To do this, we use @, which allows us to specify values ​​for an XML attribute.

...

$document = new DOMDocument();
$document->loadXML($xml);

$xpath = new DOMXpath($document);
$element = $xpath->query('/library/shelf[@identificador="D1"]//livro');

print_r($element);

And so we only get one node, as expected, because on the shelf D1 there is only the book Bitwise.

DOMNodeList Object
(
    [length] => 1
)

xpath and simple_xml_*

As we have seen, xpath allows us to search for exactly what we want in a document. But all the examples we’ve seen so far have been through DOMDOcumento for manipulating XML. What if you are using the simple\_xml_* function?

The resources offered to use xpath are the same, only their handling and return differ.

$text = '
<library>
    <book id="1">
        <name>PHP</name>
        <description>Learn PHP</description>
    </book>
</library>';

$xml = simplexml_load_string($texto);
$elements = $xml->xpath('/library/book');

print_r($elements);

Using xpath with the simplexml_* functions is even a little easier, as we don’t need to instantiate a new object like we do with DOMDocument. Using DOMXpath is a more object-oriented approach than using simple_xml_* functions, however, the resources used are the same.

Array
(
    [0] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [id] => 1
                )
            [name] => PHP
            [description] => Learn PHP
        )
)

Xpath has numerous patterns to use, such as the dot (.), which references the current node; and a colon (..), which references the node above the current node. They are very important if you cannot identify a node by a unique identifier, such as an id or the value of an attribute. For this reason, take a look at the official PHP documentation on the DOM API, at http://php.net/manual/class.domxpath.php, and on SimpleXMLElement, at http://php.net/ manual/simplexmlelement.xpath.php.

JSON encode, decode

One of the most famous data types today is JSON (Javascript Object Notation) and, with PHP, we can easily manipulate this type of data. JSON has a huge advantage over XML, as it does not have verbose markup, and is also much lighter, as it does not carry as much information as XML in its body.

The two main functions in PHP for using JSON are json_encode to transform a PHP data type into JSON, and json_decode which deserializes JSON objects to a PHP data type.

print json_encode([
    'item' => [
        'basic',
        'advanced'
    ]
]);

Calling json_encode is the simplest way to have JSON, however we can enter some more parameters for the function, such as choosing which type of bitmask we want to use.

print json_encode([
    'item' => [
        'basic',
        'advanced'
    ]
], JSON_HEX_QUOT);

We can also combine several options to apply:

print json_encode([
    'item' => [
        'basic',
        'advanced'
    ]
], JSON_HEX_QUOT | JSON_HEX_TAG);

JSON_HEX_QUOT will transform all quotation marks (") into \u0022, or we can use JSON_HEX_TAG, which will transform the signs < and > into \u003C and \u003E. PHP provides us with a list of all possible options to use, and this can be seen at http://php.net/manual/en/json.constants.php.

The last parameter we can use is the depth size that PHP will recursively traverse to transform the data into a JSON string. This is used in very large collections, where we can restrict the size of the recursion.

print json_encode([
    'item' => [
        'basic',
        'advanced'
    ]
], JSON_HEX_QUOT | JSON_HEX_TAG, 2);

And to deserialize a JSON object is very simple too. Look:

$json = '{"item":["basic","advanced"]}';

print json_decode($json);

To learn more about the JSON format, visit the official website at http://www.json.org/.

SOAP (Simple Object Access Protocol)

SOAP is a messaging protocol that allows us to communicate between applications regardless of the operating system and programming language. For this purpose, HTTP (Hypertext Transfer Protocol) and XML (Extensible Markup Language) are used as a basis.

Nowadays, we consume many services over the web, and PHP provides us with a simple and fast way to do so. Starting with version 5.0.1, we can use an abstraction to consume SOAP services or to create a SOAP server.

  • SOAP is a protocol for exchanging messages regardless of technology;
  • SOAP uses WSDL (Web Services Description Language) to describe its services;
  • SOAP uses only XML.

Consuming a SOAP service with PHP is very simple. To do this, we use the SoapClient class, and we only need the WSDL to pass as a parameter to the constructor method.

$cliente = new SoapClient('http://my.service.com?wsdl');

One point to pay attention to when using SoapClient is that we can pass an array with several options as the second parameter of the constructor method, as shown in the following table.

Option Value
style Used only when a WSDL is not provided
soap_version Specifies the version of SOAP_1_1 or SOAP_1_2 (the default used is SOAP_1_1)
compression Allows you to use compression in requests made and responses
encoding Defines which type of encoding will be used internally
trace Using this option, it is possible to trace whether an error occurred during the request (the default for this option is false)
classmap Maps a WSDL to a PHP class
exceptions Defines whether exceptions will be thrown if an error occurs (exception of type SoapFault)
connection_timeout Defines how long PHP will wait if there is no response, this option can be defined in php.ini through the default_socket_timeout
typemap Specifies three indices to map the WSDL: type_ns, the namespace name used in the WSDL; type_name, the name of the node to be mapped; and from_xml, a function defined to be used as a callback
cache_wsdl Defines the type of cache used through the constants: WSDL_CACHE_NONE, WSDL_CACHE_DISK, WSDL_CACHE_MEMORY or WSDL_CACHE_BOTH
user_agent Defines the User-Agent header to perform the request
stream_context It is possible to define a context using streams through the stream_context_create
features Defines the type of bitmask used through the constants: SOAP_SINGLE_ELEMENT_ARRAYS, SOAP_USE_XSI_ARRAY_TYPE or SOAP_WAIT_ONE_WAY_CALLS
keep_alive Through a boolean value, it defines whether the Connection: Keep-Alive header will be sent when true, or Connection: close
ssl_method Defines the type of SSL used through the constants: SOAP_SSL_METHOD_TLS, SOAP_SSL_METHOD_SSLv2, SOAP_SSL_METHOD_SSLv3 or SOAP_SSL_METHOD_SSLv23

What we need now is just to execute the desired method. If you cannot identify in the WSDL which methods we can use, we can use the __getFunctions method to return a complete list of available methods.

$cliente = new SoapClient('http://my.service.com?wsdl');
$cliente->__getFunctions();

After identifying the desired method, we have two different ways to make the call. The first is using a call directly to the SoapClient object with the name of the desired method:

$cliente = new SoapClient('http://my.service.com?wsdl');
$cliente->myMetodo(['parameter1', 'parameter2']);

Or we can use the __callSoap method, passing the desired method as the first parameter, and the arguments as the second parameter:

$parameters = [
    'parameter1' => 'value1',
    'parameter2' => 'value2',
];
$response = $soapClient->__soapCall('meuMetodo', [$parameters]);

When using the __soapCall method, we must pay close attention to how we pass the parameters, as we must encapsulate all the necessary parameters in an array (as we can see in the previous example, with the variable $parameters). And when calling the __soapCall method, we must encapsulate the parameter array in a new array again. In other words, we need to encapsulate our parameters twice before sending the request. If you do not use both parameters before making the request, you will receive an error message from the service you are consuming, claiming that the necessary parameters were not sent.

In addition to consuming SOAP-based services, we can also create our own server and provide a service with PHP to be consumed in any other language as well. For this, we use the SoapServer class.

$soapServer = new SoapServer('service.wsdl');

We can also use SoapServer, without specifying a WSDL. To do this, we must inform the uri option as a second parameter to the constructor.

$soapServer = new SoapServer(null, [
    'uri' => 'http://localhost/wsdl'
]);

And finally, we choose which class we want to expose to our service:

class MyService {
    public function hello()
    {
        return 'My service hello method';
    }
}

$soapServer->setClass('MyService');
$soapServer->handle();

php.ini and SOAP

Some caching features used by SOAP can be defined in php.ini, for example, if we want to enable the use of caching:

soap.wsdl_cache_enabled=1

We can define the directory whose cache will be stored:

soap.wsdl_cache_dir="/tmp"

Furthermore, we can also define how long we will use the cache instead of the original WSDL:

soap.wsdl_cache_ttl=86400

And finally, it is possible to define the maximum cache size that will be stored:

soap.wsdl_cache_limit = 5

REST

Just like SOAP, we can consume web services through REST (Representational State Transfer). Unlike it, in which we use our own protocol, with REST we use HTTP verbs to transmit messages. We also have the possibility of using XML or JSON. With REST, we have some roles defined for each HTTP verb that we will use:

  • GET - Used to read records.
  • POST - We use the verb POST when we want to create a new resource in the service offered.
  • PUT - Used to update an existing record and, generally, used in conjunction with GET to obtain the record you want to update.
  • PATCH - Used when we want to update only a part of the resource provided by the service.
  • DELETE - As the name suggests, used to delete records from our service.

Another very important part about REST services is their return status, in which we have information for each number range:

  • 1XX - Statuses in the range 100+ are used as informational.
  • 2XX - Statuses in the 200+ range are used to report successful operation.
  • 3XX - Statuses in the 300+ range are used to inform redirection.
  • 4XX - Statuses in the 400+ range are used to inform that there was something wrong with the request sent, that is, that the server was unable to interpret it.
  • 5XX - Statuses in the range 500+ are used to indicate internal server errors.

The complete list of HTTP statuses is available on the W3C website and can be seen at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

REST and PHP

Now that we understand what REST is and how to use it, we can join forces and understand how we can use these verbs with PHP. Interestingly, the verbs GET and POST are the easiest to manipulate, as PHP already abstracts all the complexity of a request for these verbs.

To manipulate data that is passed via GET, simply access the global $_GET, indicating the key we want:

$name = $_GET['name'];

This is possible because PHP provides an associative array with all the parameters sent in the request. The same occurs with the POST verb, as PHP provides us with an associative array with the parameters sent, exactly the same way as with the GET verb.

$name = $_POST['name'];

Things start to get a little more complicated when we talk about other verbs, like PUT. With it, we need to deal directly with the stream to retrieve this data. Unfortunately, the way to manipulate data sent via this verb is not as easy as data sent via GET or POST. However, PHP also provides us with a smooth way to access through streams.

To understand how to do this, the first thing is to create a file called rest.php to receive this data and display it:

// Reads the data sent in the request and displays

print file_get_contents('php://input');

After that, we need to access this file through our web server. In my case, I’m using the web server that comes built in with PHP, so I just go to the folder where my script is and type the following command:

php -S localhost:8989

After that, we can send our request to the web server and be processed by our PHP script. I will use CURL to make this request, but you can use extensions with POSTMAN, for example.

curl -X PUT -H "Content-Type: application/x-www-form-urlencoded" -d 'my_parameter=my_value' http://localhost:8989/rest.php

And when we execute the request, we get the following response:

my_parameter=my_value

The same occurs with the verb PATCH. We use the same request, just changing the type of verb, and we get the same response:

curl -X PATCH -H "Content-Type: application/x-www-form-urlencoded" -d 'my_parameter=my_value' http://localhost:8989/rest.php

We change the desired verb, but the answer is the same:

my_parameter=my_value

The DateTime class

In the applications we develop, at some point we will come across dates, whether displaying a date to the user or processing a date format that comes from the database. With the DateTime class, we can perform various operations on dates in an object-oriented manner.

$data = new DateTime();

The DateTime class provides us with some standard date types to be used as constants. See some examples:

ATOM = "Y-m-d\TH:i:sP" ;
COOKIE = "l, d-M-Y H:i:s T" ;
ISO8601 = "Y-m-d\TH:i:sO" ;
RFC822 = "D, d M y H:i:s O" ;
RFC850 = "l, d-M-y H:i:s T" ;
RFC1036 = "D, d M y H:i:s O" ;
RFC1123 = "D, d M Y H:i:s O" ;
RFC2822 = "D, d M Y H:i:s O" ;
RFC3339 = "Y-m-d\TH:i:sP" ;
RSS = "D, d M Y H:i:s O" ;
W3C = "Y-m-d\TH:i:sP" ;

A recommendation is that you keep in mind these constants used by DateTime for the certification test.

Some options in php.ini are directly affected using dates, such as date.timezone, which issues a warning if it is not defined.

php.ini options using dates {w=90%}

Adding an interval between dates is extremely simple, and introduces us to the first class we use together with DateTime, DateInterval.

With this class, you can add a time period to a date:

$today = new \DateTime('now');
$tomorrow = $today->add(new \DateInterval('P1D'));

The first thing we should pay attention to is the use of P in the class constructor. This type of parameter is mandatory, and means Period (Period).

In addition to the P option (mandatory), we have the following parameters to inform periods:

Option Description
Y Years
M Months
D Days
W Weeks (these weeks are converted to days internally in PHP, which makes it impossible to use W in conjunction with D)
H Hours
M Minutes
S Seconds

Now that we know how to specify interval types for DateInterval, we can add different time periods:

$today = new \DateTime('now');
$tomorrow = $today->add(new \DateInterval('P1W'));

DateTimeImmutable

DateTime and DateTimeImmutable class implementations {w=80%}

If you ran the previous examples, you will notice that if we add a period using the add method between dates, the base value of the object will also change. Let’s look at an example to simplify:

$today = new \DateTime('2015-10-10');
$tomorrow = $today->add(new \DateInterval('P1D'));

We start with a DateTime object with the date 2015-10-10, and assign the variable $today. Soon after, we add a day, that is, we will have our new date, 2015-10-11, returned from the add method.

$today = new \DateTime('2015-10-10');
$tomorrow = $today->add(new \DateInterval('P1D'));

print $tomorrow; // 2015-10-11

However, when we try to retrieve the previous day that we pass into the variable $today, we get 2015-10-11.

$today = new \DateTime('2015-10-10');
$tomorrow = $today->add(new \DateInterval('P1D'));

print $today; // 2015-10-11

This is often not the desired behavior. In many cases, we want the object to maintain its state on the dates we pass to it. In our case, we would expect the variable $hoje with the value 2015-10-10, and the variable $tomorrow with the value 2015-10-11.

To achieve this result, we must use the DateTimeImmutable class, which was only introduced in PHP 5.5, exactly to solve this behavior problem with the DateTime class.

The DateTimeImmutable class has exactly the same methods as the DateTime class, what changes is just its behavior.

$today = new \DateTimeImmutable('2015-10-10');
$tomorrow = $today->add(new \DateInterval('P1D'));

print $today; // 2015-10-10
print $tomorrow; // 2015-10-11

DateTimeImmutable was introduced in PHP 5.5, and is also a subject that falls into the certification test. It behaves exactly the same way as the DateTime class, but if you feel the need, visit the official documentation, at http://php.net/manual/en/class.datetimeimmutable.php.

Setting date

So far, we have only defined a date through the constructor, passing the date we want in a format accepted by the class:

$birthdate = new DateTime('2000-07-02');

However, we can also set a date after creating the object using the setDate method. Through it, we can provide a year, month and day for us to use.

$birthdate = new DateTime('2000-07-02');
$birthdate->setDate(2000, 7, 2);

print $birthdate->format('d/m/Y'); // 07/02/2000

Just like for date, we have a method for setting the time, which works in the same way as setDate. However, in this method, we enter the desired hours, minutes and seconds.

$birthdate = new DateTime();
$birthdate->setTime(10, 45, 10);

print $birthdate->format('h:i:s'); //10:45:10

Again, we must pay attention to the behavior of the DateTimeImmutable class compared to the DateTime class. With the DateTime class, we can define a date when creating the object and, after that, modify it successfully. See our example that changes the date from 02/07/2000 to 07/07/1990.

$birthdate = new DateTime('2000-07-02');
print $birthdate->format('d/m/Y'); // 07/02/2000

$birthdate->setDate(1990, 07, 07);
print $birthdate->format('d/m/Y'); // 07/07/1990

Nothing too out of the ordinary and expected, after all, if we are defining a new date/time for the object, we want to modify it. However, using the DateTimeImmutable class, this type of behavior is not allowed, and the date/time defined at the time of object construction is not affected. Note that changing the date from 07/02/2000 to 07/07/1990 is not possible with the DateTimeImutable class.

$birthdate = new DateTimeImmutable('2000-07-02');
print $birthdate->format('d/m/Y'); // 07/02/2000

$birthdate->setDate(1990, 07, 07);
print $birthdate->format('d/m/Y'); // 07/02/2000

Note that the result after using the setDate method does not change. Let’s look at another example, now using both date and time.

Again, we must pay attention to the behavior of the DateTimeImmutable class compared to the DateTime class. With the DateTime class, we can define a date when creating the object and, after that, modify it successfully. See our example that changes the date from 02/07/2000 to 07/07/1990.

$birthdate = new DateTime('2000-07-02');
print $birthdate->format('d/m/Y'); // 07/02/2000

$birthdate->setDate(1990, 07, 07);
print $birthdate->format('d/m/Y'); // 07/07/1990

Nothing too out of the ordinary and expected, after all, if we are defining a new date/time for the object, we want to modify it. However, using the DateTimeImmutable class, this type of behavior is not allowed, and the date/time defined at the time of object construction is not affected. Note that changing the date from 07/02/2000 to 07/07/1990 is not possible with the DateTimeImutable class.

$birthdate = new DateTimeImmutable('2000-07-02');
print $birthdate->format('d/m/Y'); // 07/02/2000

$birthdate->setDate(1990, 07, 07);
print $birthdate->format('d/m/Y'); // 07/02/2000

Note that the result after using the setDate method does not change. Let’s look at another example, now using both date and time.

$birthdate = new DateTimeImmutable('2000-07-02 10:10:10');
print $birthdate->format('d/m/Y h:i:s'); // 02/07/2000 10:10:10

// Now let's try to modify the date and time defined when the object was constructed
$birthdate->setDate(1990, 07, 07);
$birthdate->setTime(12, 10, 57);

// The date and time do not change
print $birthdate->format('d/m/Y h:i:s'); // 02/07/2000 10:10:10

sub

In addition to adding a period of time to a given date, we’ll probably want to subtract it as well. Just like the add method, which adds time periods, we can use the sub method to subtract time periods.

$today = new DateTime('2015-10-10');
$yesterday = $today->sub(new DateInterval('P1D'));

print $yesterday->format('Y-m-d'); //2015-10-09

modify

So far, we’ve seen how to use specific methods to add/subtract date periods. But PHP provides us with the modify method that allows us to modify a date in different ways. See the same result acquired with the sub method now using the modify method:

$today = new DateTime('2015-10-10');
$yesterday = $today->modify('-1 day');

print $yesterday->format('Y-m-d'); //2015-10-09

Now let’s add a period:

$today = new DateTime('2015-10-10');
$yesterday = $today->modify('+1 day');

print $yesterday->format('Y-m-d'); //2015-10-11

Using the modify method, we make our code much more readable, as we use a string to express exactly what we want to do with that period of time.

Time Zone

Another feature that stands out using DateTime is the use of time zones. Using DateTimeZone, we can define the time zones we want in our application. This gives us great flexibility in applications that need to calculate different times depending on the time zone.

We saw earlier that we can set a default time zone for PHP in php.ini:

date.timezone = America/Sao_Paulo

However, through this method, we define a default time zone for the entire application. Using DateTimeZone it is possible to set different time zones for multiple DateTime objects.

$saoPaulo = new DateTime('now', new DateTimeZone('America/Sao_Paulo'));
print $saoPaulo->format('d/m/Y H:i:s');

$auckland = new DateTime('now', new DateTimeZone('Pacific/Auckland'));
print $auckland->format('d/m/Y H:i:s');

We can also find out which time zone a given instance of DateTime is using through the getTimeZone method, which returns an instance of DateTimeZone.

print $saoPaulo->getTimeZone()->getName(); // America/Sao_Paulo

print $auckland->getTimeZone()->getName(); //Pacific/Auckland

An interesting thing to note is that if no time zone is specified for DateTime, PHP assumes the time zone defined in php.ini.

$default = new DateTime();

print $default->getTimeZone()->getName(); // Returns the option defined in date.timezone in php.ini

For more information about DateTimeZone, see the official PHP documentation, at http://php.net/manual/en/class.datetimezone.php.

createFromFormat

On some occasions, we want to create a date from a non-standard format that the language does not support on its own. For this, there is the createFromFormat method, which makes it possible to create our own formats to be used

In our example, let’s assume that we want to convert the date in the Brazilian standard (dd/mm/yyyy) to the American format (yyyy-mm-dd). This is a very common task when we need to persist data in the database.

$myFormat = \DateTime::createFromFormat('d/m/Y', '02/07/2000');

print $myFormat->format('Y-m-d'); // 2000-07-02

Remember: DateTime and DateTimeImmutable have the same methods, but different behaviors.

Summary

As in this chapter we deal with different topics, such as manipulating XML, JSON and dates, it is important to highlight knowledge of these technologies that have no direct relationship with PHP. Before continuing with the book, I advise you to familiarize yourself as much as possible with these technologies to make your experience when using PHP together with them very transparent.

To understand a little more about XML, you can access its specification at https://www.w3.org/TR/REC-xml/, and get a little deeper insight. Furthermore, on the PHP side, you can also see the library that it uses internally in functions that manipulate XML, at http://www.xmlsoft.org. The same happens with JSON. On the website http://json.org, you can see detail by detail what it is and how to use it.