Home arrow PHP arrow Page 2 - PHP: Adding Behavior to a URL Class

Extending the immutability of the Url class by adding query string parameters - PHP

In this second part of a series, I add a basic method to the “Url” class created in the first part. This method will be tasked with appending new parameters to its existing query string. Due to the immutable nature of the class, the method will return new “url” objects, in this way demonstrating the actual functionality of the Value Object pattern when it comes to taking immutability to a more complex level.

TABLE OF CONTENTS:
  1. PHP: Adding Behavior to a URL Class
  2. Extending the immutability of the Url class by adding query string parameters
By: Alejandro Gervasio
Rating: starstarstarstarstar / 2
November 03, 2010

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

To be frank, the full functionality of the Value Object pattern is leveraged when the implementation of a method tries to modify in some way the values assigned to an immutable class. To elaborate on this concept, below is the implementation of a brand new method corresponding to the earlier “Url” class. It adds some arguments (or attempts to do so) to its $_queryString field. Check it out:

// add new query string parameters (returns a new Url object)
public function addQueryString(array $params)
{
    if (empty($params)) {
        throw new UrlException('The specified query string parameters are invalid.');
    }
   
    $queryString = '';
    foreach ($params as $key => $value) {
        $queryString .= '&' . $key . '=' . urlencode($value);
    }
    $queryString = $this->_queryString === null ?
                 trim($queryString, '&') :
                 $this->_queryString . $queryString;
    $url = $this->_scheme . '://' . $this->_host . $this->_path . '?' . $queryString;
    return new Url($url);
}

That looks pretty interesting, doesn’t it? As you can see, the above “addQueryString()” method takes an associative array as an incoming argument, and each key/value pair is added to the query string of the class. While this process is pretty self-explanatory, the most relevant aspect of the method it that instead of modifying the existing query string, it creates a new one which is used to also create a new URL, which in turn is utilized to spawn a new “Url” object.

This shows the nature of an immutable value object: yes, any attempt to alter the values assigned to its existing fields will result in the creation of a new value object of the same type, thus properly preserving its immutability.

And now that you've surely grasped the logic of the “addQueryString()” function, here’s the finished version of the “Url” class, after including the function into its source code:

(Url.php)

<?php

final class Url
{
    private $_scheme; 
    private $_host;
    private $_path;
    private $_queryString;
   
    // constructor
    public function __construct($url)
    {
        if (!filter_var($url, FILTER_VALIDATE_URL, array(FILTER_FLAG_SCHEME_REQUIRED, FILTER_FLAG_HOST_REQUIRED))) {
            throw new UrlException('The specified URL is invalid.');
        }
       
        $url = parse_url($url);
        $this->_scheme = $url['scheme'];
        $this->_host = $url['host'];
       
        if (isset($url['path'])) {
            $this->_path = $url['path'];
        }
       
        if (isset($url['query'])) {
            $this->_queryString = $url['query'];
        }
    }
   
    // get the scheme part of the URL
    public function getScheme()
    {
        return $this->_scheme;
    }
   
    // get the host part of the URL
    public function getHost()
    {
        return $this->_host;
    }
   
    // get the path part of the URL
    public function getPath()
    {
        return $this->_path;
    }
   
    // get the query string of the URL
    public function getQueryString()
    {
        return $this->_queryString;
    }
   
    // add new query string parameters (returns a new Url object)
    public function addQueryString(array $params)
    {
        if (empty($params)) {
            throw new UrlException('The specified query string parameters are invalid.');
        }
       
        $queryString = '';
        foreach ($params as $key => $value) {
            $queryString .= '&' . $key . '=' . urlencode($value);
        }
        $queryString = $this->_queryString === null ?
                     trim($queryString, '&') :
                     $this->_queryString . $queryString;
        $url = $this->_scheme . '://' . $this->_host . $this->_path . '?' . $queryString;
        return new Url($url);
    }                
}

Done. At this point, the “Url” class is complete and ready to be tested. Therefore, in the next section I’m going to set up a simple example, which will demonstrate how to create a couple of value objects using the class.

Of course, if you’re like me it’s probable that you’re wondering if those objects will be really immutable. Well, the only way to get your question answered is by looking at the example. So hurry up and read the following section.   

Building a final example: putting the Value Object pattern into action

As I promised in the section that you just read, I've included a minimalist example that shows the immutable nature of the previous “Url” class. Take a close look at it, please:

<?php

require_once 'Url.php';

// create a new Url object
$url1 = new Url('http://www.devshed.com');

// append some query string params to the previous URL (returns a new Url object)
$url2 = $url1->addQueryString(array('userid' => '1', 'name' => 'Alex'));

if ($url1 == $url2) {
    echo 'The two value URL objects are equal.';
}
else {
    echo 'The two value URL objects are not equal.';
}

/*
displays the following
The two value URL objects are not equal.
*/

In this case, the above script starts creating a new value object, which is properly populated with a well-formed URL; then, a second object is generated by calling the “addQueryString()” method (remember that this one is basically a factory).

With these two objects living comfortably side by side, a trivial comparison (note the use of the “==” operator) is made in order to determine if the objects in question are equal, not identical. As one might expect, the result of this process is false, which demonstrates the immutability of the involved objects.

Needless to say, it’s possible to add more methods to the “Url” class which try to modify the initial values assigned to its properties, similar to the “addQueryString()” function that you learned before. In all cases, these methods should return new URL objects, regardless of the form of processing applied to the pertinent fields.
 
Final thoughts

In this second part of the series, I added to the previous “Url” class a basic method which was tasked with appending new parameters to its existing query string. Due to the immutable nature of the class, the method returned new “Url” objects, thus demonstrating the actual functionality of the Value Object pattern when it comes to taking immutability to a more complex level.

With this method properly implemented, it was easy to illustrate how to use it for creating new value objects upon its invocation. Moreover, this process showed a key concept of a value object: any type of additional processing applied to the object will result in the creation of a new one, usually via a factory method. Do you understand? I bet you do.

Naturally, it’s possible to model value objects that are different from the ones that you saw in the previous example. In line with this idea, in the next part I’m going to show how to apply the Value Object pattern to a class responsible for creating simple HTML widgets.

Don’t miss the upcoming tutorial!



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: