HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

URI parsing and handling class

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
handlinguriparsingandclass

Problem

I wrote a simple class to deal with parsing and handling URIs for the project I'm currently working on, since it relies a lot on that functionality (eg the Router class and some HTML helpers). Here is the code already commented:

```
scheme = $matches[2];

# Extract the URI authority from the string
if(array_key_exists(4, $matches)) $authority = $matches[4];

# Extract the URI path from the string
if(array_key_exists(5, $matches)) $this->path = $matches[5];

# Extract the URI query from the string
if(array_key_exists(7, $matches)) $this->query = $matches[7];

# Extract the URI fragment from the string
if(array_key_exists(9, $matches)) $this->fragment = $matches[9];

# Extract username, password, host and port from authority
preg_match('"(([^:@])(:([^:@]))?@)?([^:])(:(.))?"', $authority, $matches);

# Extract the URI username from the authority part
if(array_key_exists(2, $matches)) $this->user = $matches[2];

# Extract the URI password from the authority part
if(array_key_exists(4, $matches)) $this->password = $matches[4];

# Extract the URI hostname from the authority part
if(array_key_exists(5, $matches)) $this->host = $matches[5];

# Extract the URI port from the authority part
if(array_key_exists(7, $matches)) $this->port = $matches[7];

# Get the rid of the leading path slash if its present in the string
if(substr($this->path, 0, 1) == '/') $this->path = substr($this->path, 1);

# Get the rid of the ending path slash if its present in the string
if(substr($this->path, -1, 1) == '/') $this->path = substr($this->path, 0, -1);

# Set the path to an array by exploding it with the default delimiter
$this->path = explode('/', $this->path);

# Make sure that the array i

Solution

Information Hiding

Your class contains all public properties and methods.

This means that users of the class are exposed to all of the internal properties, causing the following problems:

  • Confusion - With so many publicly accessible properties and methods the user doesn't know which property or method to interact with first. There are more choices for them to look at.



  • Accident Prone - The user has full power over the public properties. This could lead them to modify them in harmful ways (accidentally). Without restricting the access to only tested public methods we cannot limit the scope of possible errors (accidents) that can be created.



Work in the Constructor

Your constructor does real work rather than just configuring the object.

Doing real work in the constructor makes it harder for you to test and extend from this class. Miško Hevery says it better than i could here.

Suggested Interface

I would try to keep the interface as simple as possible. What I suggest below is mainly to take the work away from the constructor. You can modify it to your own needs.

class uri
{
    # URI scheme
    protected $scheme;

    # URI host
    protected $host;

    # URI user
    protected $user;

    # URI password
    protected $password;

    # URI port
    protected $port;

    # URI path
    protected $path;

    # URI query
    protected $query;

    # URI fragment
    protected $fragment;

    # Default constructor for the URI
    public function __construct()
    {
        # No setup required.
    }

    # Set the URI current URI.
    public function setCurrent()
    {
        # I would also use isset rather than array_key_exists in this case.
        # $_SERVER['HTTP'] does not exist, use an if/else on the HTTPS key.
        # The property values can be set directly.

        # This is basically the if($uri == null) {} code.
        $this->scheme = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';

        if (isset($_SERVER['SERVER_NAME']))
        {
            $this->host = $_SERVER['SERVER_NAME'];
        }

        if (isset($_SERVER['REQUEST_URI']))
        {
            # Process the URI into the object properties.
        }
    }

    # Set the URI from a string according to RFC 2396 (appendix B)
    public function setFromString($uri)
    {
        if (!is_string($uri))
        {
            throw new \InvalidArgumentException(
                __METHOD__ . ' uri must be a string.');
        }

        # if($uri != null and !is_array($uri)) {} code goes here.       
    }

    # An URI is provided in array form
    public function setFromArray(Array $uri)
    {
        # if($uri != null and is_array($uri)) {} code goes here.
    }

    # Returns the URI as a string.
    public function __toString()
    {
        # Ensure that all required properties are set.
        if (!isset($this->host, $this->scheme)) # etc.
        {
            throw new \BadMethodCallException(
                __METHOD__ . ' url properties have not been set.');
        }

        $uri = $this->scheme . $this->host;

        if (isset($this->query))
        {
            # Add optional uri part here.
        }
    }
}

Code Snippets

class uri
{
    # URI scheme
    protected $scheme;

    # URI host
    protected $host;

    # URI user
    protected $user;

    # URI password
    protected $password;

    # URI port
    protected $port;

    # URI path
    protected $path;

    # URI query
    protected $query;

    # URI fragment
    protected $fragment;

    # Default constructor for the URI
    public function __construct()
    {
        # No setup required.
    }

    # Set the URI current URI.
    public function setCurrent()
    {
        # I would also use isset rather than array_key_exists in this case.
        # $_SERVER['HTTP'] does not exist, use an if/else on the HTTPS key.
        # The property values can be set directly.

        # This is basically the if($uri == null) {} code.
        $this->scheme = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';

        if (isset($_SERVER['SERVER_NAME']))
        {
            $this->host = $_SERVER['SERVER_NAME'];
        }

        if (isset($_SERVER['REQUEST_URI']))
        {
            # Process the URI into the object properties.
        }
    }

    # Set the URI from a string according to RFC 2396 (appendix B)
    public function setFromString($uri)
    {
        if (!is_string($uri))
        {
            throw new \InvalidArgumentException(
                __METHOD__ . ' uri must be a string.');
        }

        # if($uri != null and !is_array($uri)) {} code goes here.       
    }

    # An URI is provided in array form
    public function setFromArray(Array $uri)
    {
        # if($uri != null and is_array($uri)) {} code goes here.
    }

    # Returns the URI as a string.
    public function __toString()
    {
        # Ensure that all required properties are set.
        if (!isset($this->host, $this->scheme)) # etc.
        {
            throw new \BadMethodCallException(
                __METHOD__ . ' url properties have not been set.');
        }

        $uri = $this->scheme . $this->host;

        if (isset($this->query))
        {
            # Add optional uri part here.
        }
    }
}

Context

StackExchange Code Review Q#9114, answer score: 2

Revisions (0)

No revisions yet.