Home arrow PHP arrow PHP Service Layers: A Final Example

PHP Service Layers: A Final Example

If youíre looking for an approachable guide that teaches you how to implement an easily-customizable service layer in PHP, then take a peek at this article series. In a step-by-step fashion, it walks you through the development of a sample web application, which uses a service to perform CRUD operations on a domain model composed of a few user entities.

TABLE OF CONTENTS:
  1. PHP Service Layers: A Final Example
  2. The service in action: fetching user entities from
By: Alejandro Gervasio
Rating: starstarstarstarstar / 0
October 17, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

And now that you know what to expect, itís tiem to recap the topics discussed in the last installment. In that tutorial, I constructed a pair of dependency injection containers, along with a static helper. These allowed us to shield from client code the creation of the object graph corresponding to the user service.

With the implementation of these additional elements, the scene is finally set to put the service into action and see if it is actually as functional as it seems.

In this last chapter Iíll be creating a concrete example that will show you how to use the service to retrieve, save and delete user objects from a simple MySQL database. And thanks to the serviceís inherent flexibility, youíll be able to adapt it to work with your existing infrastructure (read your framework) and even with different client layers.

Now, leave the dull theory behind and start reading!

Putting all of the pieces together: showing the applicationís full source code
 
First things first. Before I demonstrate how to put the sample application previously developed (and its user service, of course) to work, itíd be useful to list its full source code. This way you can have its building blocks available in one place, in case you want to alter them to suit your personal needs.

Having said that, are you ready to digest a huge amount of code samples? Great. So, this heavy roundup begins with the applicationís domain layer. Here it is:

(MyApplication/Entity/AbstractEntity.php)

<?php

namespace MyApplicationEntity;

abstract class AbstractEntity
{
    protected $_values = array();
    protected $_allowedFields = array();
   
    /**
     * Class constructor
     */
    public function __construct(array $data)
    {
        foreach ($data as $name => $value) {
            $this->$name = $value;
        }
    }
   
    /**
     * Assign a value to the specified field via the corresponding mutator (if it exists);
     * otherwise, assign the value directly to the '$_values' protected array
     */
    public function __set($name, $value)
    {  
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.'); 
        }
        $mutator = 'set' . ucfirst($name);
        if (method_exists($this, $mutator) && is_callable(array($this, $mutator))) {
            $this->$mutator($value);          
        }
        else {
            $this->_values[$name] = $value;
        }   
    }
   
    /**
     * Get the value assigned to the specified field via the corresponding getter (if it exists);
    otherwise, get the value directly from the '$_values' protected array
     */
    public function __get($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');   
        }
        $accessor = 'get' . ucfirst($name);
        if (method_exists($this, $accessor) && is_callable(array($this, $accessor))) {
            return $this->$accessor;   
        }
        if (isset($this->_values[$name])) {
            return $this->_values[$name];  
        }
        throw new EntityException('The field ' . $name . ' has not been set for this entity yet.');
    }

    /**
     * Check if the specified field has been assigned to the entity
     */
    public function __isset($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');
        }
        return isset($this->_values[$name]);
    }

    /**
     * Unset the specified field from the entity
     */
    public function __unset($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException('The field ' . $name . ' is not allowed for this entity.');
        }
        if (isset($this->_values[$name])) {
            unset($this->_values[$name]);
        }
    }

    /**
     * Get an associative array with the values assigned to the fields of the entity
     */
    public function toArray()
    {
        return $this->_values;
    }             
}

 

(MyApplication/Entity/User.php)

<?php

namespace MyApplicationEntity;

class User extends AbstractEntity
{  
    protected $_allowedFields = array('id', 'fname', 'lname', 'email');
   
    /**
     * Set the user's ID
     */
    public function setId($id)
    {
        if(!filter_var($id, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 999999)))) {
            throw new EntityException('The specified ID is invalid.');
        }
        $this->_values['id'] = $id;
    }
   
    /**
     * Set the user's first name
     */ 
    public function setFname($fname)
    {
        if (strlen($fname) < 2 || strlen($fname) > 32) {
            throw new EntityException('The specified first name is invalid.');
        }
        $this->_values['fname'] = $fname;
    }
       
    /**
     * Set the user's last name
     */
    public function setLname($lname)
    {
        if (strlen($lname) < 2 || strlen($lname) > 32) {
            throw new EntityException('The specified last name is invalid.');
        }
        $this->_values['lname'] = $lname;
    }
   
    /**
     * Set the user's email address
     */
    public function setEmail($email)
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new EntityException('The specified email address is invalid.');
        }
        $this->_values['email'] = $email;
    }                   
}

 

(MyApplication/Entity/EntityException.php)

<?php

namespace MyApplicationEntity;

class EntityException extends Exception{}

Done. Having listed the applicationís domain model, which in this case is responsible for spawning user entities, itís time to show the following layer. This one is made up of a couple of data mappers, along with a segregated interface, and its source code looks like this:

(MyApplication/Mapper/DataMapperInterface.php)

<?php

namespace MyApplicationMapper;

interface DataMapperInterface
{
    public function findById($id);

    public function findAll();

    public function search($criteria);

    public function insert($entity);

    public function update($entity);

    public function delete($entity);
}

 

(MyApplication/Mapper/AbstractDataMapper.php)

<?php

namespace MyApplicationMapper;
use MyApplicationDatabase,
    MyApplicationCollection;

abstract class AbstractDataMapper implements DataMapperInterface
{
    protected $_adapter;
    protected $_collection;
    protected $_entityTable;
    protected $_entityClass;

    /**
     * Constructor
     */
    public function  __construct(DatabaseDatabaseAdapterInterface $adapter, CollectionAbstractCollection $collection, array $entityOptions = array())
    {
        $this->_adapter = $adapter;
        $this->_collection = $collection;
        if (isset($entityOptions['entityTable'])) {
            $this->setEntityTable($entityOptions['entityTable']);
        }
        if (isset($entityOptions['entityClass'])) {
            $this->setEntityClass($entityOptions['entityClass']);
        }
    }

    /**
     * Get the database adapter
     */
    public function getAdapter()
    {
        return $this->_adapter;
    }

    /**
     * Get the collection
     */
    public function getCollection()
    {
        return $this->_collection;
    }

    /**
     * Set the entity table
     */
    public function setEntityTable($entityTable)
    {
        if (!is_string($table) || empty($entityTable)) {
            throw new DataMapperException('The specified entity table is invalid.');
        }
        $this->_entityTable = $entityTable;
    }

    /**
     * Get the entity table
     */
    public function getEntityTable()
    {
        return $this->_entityTable;
    }

    /**
     * Set the entity class
     */
    public function setEntityClass($entityClass)
    {
        if (!class_exists($entityClass)) {
            throw new DataMapperException('The specified entity class is invalid.');
        }
        $this->_entityClass = $entityClass;
    }

    /**
     * Get the entity class
     */
    public function getEntityClass()
    {
        return $this->_entityClass;
    }

    /**
     * Find an entity by its ID
     */
    public function findById($id)
    {
        $this->_adapter->select($this->_entityTable, "id = $id");
        if ($data = $this->_adapter->fetch()) {
            return new $this->_entityClass($data);
        }
        return null;
    }

    /**
     * Find all the entities
     */
    public function findAll()
    {
        $this->_adapter->select($this->_entityTable);
        while ($data = $this->_adapter->fetch($this->_entityTable)) {
            $this->_collection[] = new $this->_entityClass($data);
        }
        return $this->_collection;
    }

    /**
     * Find all the entities that match the specified criteria
     */
    public function search($criteria)
    {
        $this->_adapter->select($this->_entityTable, $criteria);
        while ($data = $this->_adapter->fetch()) {
            $this->_collection[] = new $this->_entityClass($data);
        }
        return $this->_collection;
    }
   
    /**
     * Insert a new row in the table corresponding to the specified entity
     */
    public function insert($entity)
    {
        if ($entity instanceof $this->_entityClass) {
            return $this->_adapter->insert($this->_entityTable, $entity->toArray());
        }
        throw new DataMapperException('The specified entity is not allowed for this mapper.');
    }

    /**
     * Update the row in the table corresponding to the specified entity
     */
    public function update($entity)
    {
        if ($entity instanceof $this->_entityClass) {
            $data = $entity->toArray();
            $id = $entity->id;
            unset($data['id']);
            return $this->_adapter->update($this->_entityTable, $data, "id = $id");
        }
        throw new DataMapperException('The specified entity is not allowed for this mapper.');
    }

    /**
     * Delete the row in the table corresponding to the specified entity or ID
     */
    public function delete($id)
    {
        if ($id instanceof $this->_entityClass) {
            $id = $id->id;
        }
        return $this->_adapter->delete($this->_entityTable, "id = $id");
    }
}

 

(MyApplication/Mapper/UserMapper.php)

<?php

namespace MyApplicationMapper;
use MyApplicationDatabase,
    MyApplicationCollection;

class UserMapper extends AbstractDataMapper
{
    protected $_entityClass = 'MyApplicationEntityUser';
    protected $_entityTable = 'users'; 
   
    /**
     * Constructor
     */
     public function __construct(DatabaseDatabaseAdapterInterface $adapter, CollectionUserCollection $collection)
     {
         parent::__construct($adapter, $collection);
     }  
}

 

(MyApplication/Mapper/DataMapperException.php)

<?php

namespace MyApplicationMapper;

class DataMapperException extends Exception{}

That wasnít too long to read, was it? Now that you've reviewed the mapping layer, we're going to look at the layer that persists the model in a MySQL database. Here it is:

(MyApplication/Database/DatabaseAdapterInterface.php)

<?php

namespace MyApplicationDatabase;

interface DatabaseAdapterInterface
{
    function connect();
   
    function disconnect(); 
   
    function query($query);
   
    function fetch(); 
   
    function select($table, $conditions, $fields, $order, $limit, $offset);
   
    function insert($table, array $data);
   
    function update($table, array $data, $conditions);
   
    function delete($table, $conditions);
   
    function getInsertId();
   
    function countRows();
   
    function getAffectedRows();
}

 

(MyApplication/Database/MysqlAdapter.php)

<?php

namespace MyApplicationDatabase;

class MysqlAdapter implements DatabaseAdapterInterface
{
    protected $_config = array();
    protected $_link;
    protected $_result;
   
    /**
     * Constructor
     */
    public function __construct(array $config)
    {
        if (count($config) !== 4) {
            throw new MySQLAdapterException('Invalid number of connection parameters.');  
        }
        $this->_config = $config;
    }
   
    /**
     * Connect to MySQL
     */
    public function connect()
    {
        // connect only once
        if ($this->_link !== null) {
            return $this->_link;
        }
        list($host, $user, $password, $database) = $this->_config;
        if (($this->_link = @mysqli_connect($host, $user, $password, $database))) {
            unset($host, $user, $password, $database);
            return $this->_link;
        }
        throw new MySQLAdapterException('Error connecting to the server : ' . mysqli_connect_error());
    }

    /**
     * Execute the specified query
     */
    public function query($query)
    {
        if (!is_string($query) || empty($query)) {
            throw new MySQLAdapterException('The specified query is not valid.');  
        }
        // lazy connect to MySQL
        $this->connect();
        if ($this->_result = mysqli_query($this->_link, $query)) {
            return $this->_result;
        }
        throw new MySQLAdapterException('Error executing the specified query ' . $query . mysqli_error($this->_link));
    }
   
    /**
     * Perform a SELECT statement
     */
    public function select($table, $where = '', $fields = '*', $order = '', $limit = null, $offset = null)
    {
        $query = 'SELECT ' . $fields . ' FROM ' . $table
               . (($where) ? ' WHERE ' . $where : '')
               . (($limit) ? ' LIMIT ' . $limit : '')
               . (($offset && $limit) ? ' OFFSET ' . $offset : '')
               . (($order) ? ' ORDER BY ' . $order : '');
        $this->query($query);
        return $this->countRows();
    }
   
    /**
     * Perform an INSERT statement
     */ 
    public function insert($table, array $data)
    {
        $fields = implode(',', array_keys($data));
        $values = implode(',', array_map(array($this, 'quoteValue'), array_values($data)));
        $query = 'INSERT INTO ' . $table . ' (' . $fields . ') ' . ' VALUES (' . $values . ')';
        $this->query($query);
        return $this->getInsertId();
    }
   
    /**
     * Perform an UPDATE statement
     */
    public function update($table, array $data, $where = '')
    {
        $set = array();
        foreach ($data as $field => $value) {
            $set[] = $field . '=' . $this->quoteValue($value);
        }
        $set = implode(',', $set);
        $query = 'UPDATE ' . $table . ' SET ' . $set
               . (($where) ? ' WHERE ' . $where : '');
        $this->query($query);
        return $this->getAffectedRows(); 
    }
   
    /**
     * Perform a DELETE statement
     */
    public function delete($table, $where = '')
    {
        $query = 'DELETE FROM ' . $table
               . (($where) ? ' WHERE ' . $where : '');
        $this->query($query);
        return $this->getAffectedRows();
    }
   
    /**
     * Escape the specified value
     */
    public function quoteValue($value)
    {
        $this->connect();
        if ($value === null) {
            $value = 'NULL';
        }
        else if (!is_numeric($value)) {
            $value = "'" . mysqli_real_escape_string($this->_link, $value) . "'";
        }
        return $value;
    }
   
    /**
     * Fetch a single row from the current result set (as an associative array)
     */
    public function fetch()
    {
        if ($this->_result !== null) {
            if (($row = mysqli_fetch_array($this->_result, MYSQLI_ASSOC)) !== false) {
                return $row;
            }
            $this->freeResult();
            return false;
        }
        return null;
    }

    /**
     * Get the insertion ID
     */
    public function getInsertId()
    {
        return $this->_link !== null ?
               mysqli_insert_id($this->_link) :
               null;
    }
   
    /**
     * Get the number of rows returned by the current result set
     */ 
    public function countRows()
    {
        return $this->_result !== null ?
               mysqli_num_rows($this->_result) :
               0;
    }
   
    /**
     * Get the number of affected rows
     */
    public function getAffectedRows()
    {
        return $this->_link !== null ?
               mysqli_affected_rows($this->_link) :
               0;
    }
   
    /**
     * Free up the current result set
     */
    public function freeResult()
    {
        if ($this->_result !== null) {
            mysqli_free_result($this->_result);
            return true;
        }
        return false;
    }
   
    /**
     * Close explicitly the database connection
     */
    public function disconnect()
    {
        if ($this->_link !== null) {
            mysqli_close($this->_link);
            $this->_link = null;
            return true;
        }
        return false;
    }
   
    /**
     * Close automatically the database connection when the instance of the class is destroyed
     */
    public function __destruct()
    {
        $this->disconnect();
    }
}

 

(MyApplication/Database/MysqlAdapterException.php)

<?php

namespace MyApplicationDatabase;

class MysqlAdapterException extends Exception{}

Still with me? Good. Having listed the applicationís data access layer, itís time to check the layer tasked with handling collections of entities. I decided to place this layer under a directory called ďCollection;Ē however, if you think it should be part of the mapping layer, feel free to make that change. In either case, the source code of this layer is as follows:

(MyApplication/Collection/AbstractCollection.php)

<?php

namespace MyApplicationCollection;

abstract class AbstractCollection implements Iterator, Countable, ArrayAccess
{
    protected $_entities = array();
    protected $_entityClass;

    /**
     * Constructor
     */
    public function  __construct(array $entities = array())
    {
        if (!empty($entities)) {
            $this->_entities = $entities;
        }
        $this->rewind();
    }

    /**
     * Get the entities stored in the collection
     */
    public function getEntities()
    {
        return $this->_entities;
    }
   
    /**
     * Clear the collection
     */
    public function clear()
    {
        $this->_entities = array();
    }
    
    /**
     * Reset the collection (implementation required by Iterator Interface)
     */    
    public function rewind()
    {
        reset($this->_entities);
    }
   
    /**
     * Get the current entity in the collection (implementation required by Iterator Interface)
     */
    public function current()
    {
        return current($this->_entities);
    }
   
    /**
     * Move to the next entity in the collection (implementation required by Iterator Interface)
     */
    public function next()
    {
        next($this->_entities);
    }
   
    /**
     * Get the key of the current entity in the collection (implementation required by Iterator Interface)
     */
    public function key()
    {
        return key($this->_entities);
    }
   
    /**
     * Check if there're more entities in the collection (implementation required by Iterator Interface)
     */
    public function valid()
    {
        return ($this->current() !== false);
    }
   
    /**
     * Count the number of entities in the collection (implementation required by Countable Interface)
     */
    public function count()
    {
        return count($this->_entities);
    }
   
    /**
     * Add an entity to the collection (implementation required by ArrayAccess interface)
     */
    public function offsetSet($key, $entity)
    {
        if ($entity instanceof $this->_entityClass) {
            if (!isset($key)) {
                $this->_entities[] = $entity;
            }
            else {
                $this->_entities[$key] = $entity;
            }
            return true;
        }
        throw new CollectionException('The specified entity is not allowed for this collection.');
    }
   
    /**
     * Remove an entity from the collection (implementation required by ArrayAccess interface)
     */
    public function offsetUnset($key)
    {
        if ($key instanceof $this->_entityClass) {
            $this->_entities = array_filter($this->_entities, function ($v) use ($key) {
                return $v !== $key;
            });
            return true;
        }
        if (isset($this->_entities[$key])) {
            unset($this->_entities[$key]);
            return true;
        }
        return false;
    }
   
    /**
     * Get the specified entity in the collection (implementation required by ArrayAccess interface)
     */
    public function offsetGet($key)
    {
        return isset($this->_entities[$key]) ?
               $this->_entities[$key] :
               null;
    } 
   
    /**
     * Check if the specified entity exists in the collection (implementation required by ArrayAccess interface)
     */    
    public function offsetExists($key)
    {
        return isset($this->_entities[$key]);
    }
}

 

(MyApplication/Collection/UserCollection.php)

<?php

namespace MyApplicationCollection;

class UserCollection extends AbstractCollection
{
    protected $_entityClass = 'MyApplicationEntityUser';

 

(MyApplication/Collection/CollectionException.php)

<?php

namespace MyApplicationCollection;

class CollectionException extends Exception{}
  
Definitely, understanding the functionality of the above array collection classes is a pretty straightforward process. So, the next thing I'll show you is the applicationís service layer. Here it is:

(MyApplication/Service/AbstractService.php)

<?php

namespace MyApplicationService;
use MyApplicationMapper,
    MyApplicationEntity;

abstract class AbstractService
{
    protected $_mapper;

    /**
     * Constructor
     */
    public function  __construct(MapperAbstractDataMapper $mapper)
    {
        $this->_mapper = $mapper;
    }

    /**
     * Find an entity by their ID
     */
    public function findById($id)
    {
        return $this->_mapper->findById($id);
    }

    /**
     * Find all the entities
     */
    public function findAll()
    {
        return $this->_mapper->findAll();
    }

    /**
     * Insert a new entity
     */
    public function insert(EntityEntityAbstract $entity)
    {
        return $this->_mapper->insert($entity);
    }

    /**
     * Update an entity
     */
    public function update(EntityEntityAbstract $entity)
    {
        return $this->_mapper->update($entity);
    }

    /**
     * Delete an entity
     */
    public function delete($id)
    {
        return $this->_mapper->delete($id);
    }
}

 

(MyApplication/Service/UserService.php)

<?php

namespace MyApplicationService;
use MyApplicationMapper,
    MyApplicationEntity;

class UserService extends AbstractService
{
    /**
     * Constructor
     */
    public function  __construct(MapperUserMapper $mapper)
    {
        parent::__construct($mapper);
    }

    /**
     * Save a user to persistence layer
     */
    public function save(EntityUser $user)
    {
        return $user->id === null ?
               $this->insert($user) :
               $this->update($user);
    }

    /**
     * Fetch all users in XML format
     */
    public function toXML()
    {
        $users = $this->_mapper->findAll();
        $xml = "<?xml version="1.0" encoding="UTF-8"?>n<users>n";
        foreach($users as $user) {
            $xml .= "<user>n<fname>$user->fname</fname>n"
                  . "<lname>$user->lname</lname>n"
                  . "<email>$user->fname</email>n</user>n";
        }
        $xml .= "</users>";
        return $xml;
    }
}

 

(MyApplication/Service/ServiceLocator.php)

<?php

namespace MyApplicationService;
use MyApplicationInjector;

class ServiceLocator
{
    protected static $_services = array();
    protected static $_injectors = array();

    /**
     * Protected constructor
     */
    protected function  __construct(){}

    /**
     * Add a single injector
     */
    public static function addInjector($name, InjectorInjectorInterface $injector)
    {
        if (!isset(self::$_injectors[$name])) {
            self::$_injectors[$name] = $injector;
            return true;
        }
        return false;
    }

    /**
     * Add multiple injectors
     */
    public static function addInjectors(array $injectors)
    {
        foreach ($injectors as $injector) {
            self::addInjector($injector);
        }
    }

    /**
     * Remove an existing injector
     */
    public static function removeInjector($name)
    {
        if (isset(self::$_injectors[$name])) {
            unset(self::$_injectors[$name]);
            return true;
        }
        return false;
    }
   
    /**
     * Get the specified injector
     */
    public static function getInjector($name)
    {
        return isset(self::$_injectors[$name]) ?
               self::$_injectors[$name] :
               null;
    }
   
    /**
     * Check if the specified injector exists
     */
    public static function injectorExists($name)
    {
        return isset(self::$_injectors[$name]);
    }

    /**
     * Add a service
     */
    public static function addService($name, AbstractService $service)
    {
        if (!isset(self::$_services[$name])) {
            self::$_services[$name] = $service;
            return true;
        }
        return false;
    }

    /**
     * Add multiple services
     */
    public static function addServices(array $services)
    {
        foreach($services as $service) {
            self::addService($service);
        }
    }

    /**
     * Remove an existing service
     */
    public static function removeService($name)
    {
        if (isset(self::$_services[$name])) {
            unset(self::$_services[$name]);
            return true;
        }
        return false;
    }

    /**
     * Get the specified service (if not created already, the associated injector builds the service)
     */
    public static function getService($name)
    {
        // if the service has been added and cached, get it from the cache
        if (isset(self::$_services[$name])) {
            return self::$_services[$name];
        }
        // otherwise, attempt to build the service via the associated injector and save it to the cache
        if (!$injector = self::getInjector($name)) {
            throw new ServiceLocatorException('Unable to get the injector associated to the specified service.');
        }
        $service = $injector->create();
        self::addService($name, $service);
        return $service;
    }

    /**
     * Check if the specified service exists
     */
    public static function serviceExists($name)
    {
        return isset(self::$_services[$name]);
    }
}

 

(MyApplication/Service/ServiceLocatorException.php)

<?php

namespace MyApplicationService;

class ServiceLocatorException extends Exception{}

Indeed, that was a lot to digest! But donít rest yet; thereís one more layer to show. This one is charged with implementing the corresponding dependency injection containers, and its source code looks like this:

(MyApplication/Injector/InjectorInterface.php)

<?php

namespace MyApplicationInjector;

interface InjectorInterface
{
    public function create();
}

 

(MyApplication/Injector/MysqlAdapterInjector.php)

<?php

namespace MyApplicationInjector;
use MyApplicationDatabase;

class MysqlAdapterInjector implements InjectorInterface
{
    protected $_mysqlAdapter;

    /**
     * Create an instance of the MysqlAdapter class
     */
    public function create()
    {
        if ($this->_mysqlAdapter === null) {
            $this->_mysqlAdapter = new DatabaseMysqlAdapter(array('host', 'user', 'password', 'database'));
        }
        return $this->_mysqlAdapter;
    }
}

 

(MyApplication/Injector/UserServiceInjector.php)

<?php

namespace MyApplicationInjector;
use MyApplicationDatabase,
    MyApplicationCollection,
    MyApplicationMapper,
    MyApplicationService;

class UserServiceInjector implements InjectorInterface
{
    /**
     * Create a user service
     */
    public function create()
    {
        $mysqlInjector = new MysqlAdapterInjector;
        $adapter = $mysqlInjector->create();
        return new ServiceUserService(
            new MapperUserMapper($adapter,
                new CollectionUserCollection
            )
        );
    }
}

Itís hard to believe, but we've finally accomplished our mission. At this point, you have at your disposal (from top to bottom, literally) the source code for this example application. But hold on a second! Since working with this user service requires a huge number of classes, Iím going to appeal to the functionality of an autoloader to lazy-load them.

This autoloader is similar to others that you've seen here at the Developer Shed Network. Its implementation is as follows:  

(MyApplication/Loader/Autoloader.php)

<?php

namespace MyApplicationLoader;

class Autoloader
{
    private static $_instance;
   
    /**
     * Get the Singleton instance of the autoloader
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self;
        }
        return self::$_instance;
    } 
   
    /**
     * Reset the instance of the autoloader
     */
    public static function resetInstance()
    {
        self::$_instance = null;
    }
   
    /**
     * Class constructor
     */
    private function __construct()
    {
        spl_autoload_register(array(__CLASS__, 'load'));
    }
   
    /**
     * Prevent to clone the instance of the autoloader
     */
    private function __clone(){}

    /**
     * Load a given class or interface
     */
    public static function load($class)
    {
        $file = str_replace(array('MyApplication', ''), array('', '/'), $class) . '.php';
        require $file;
        if (!class_exists($class) && !interface_exists($class)) {
            throw new AutoloaderException('The requested class or interface' . $class . ' was not found.');
        }
    }  
}

 

(MyApplication/Loader/AutoloaderException.php)

<?php

namespace MyApplicationLoader;

class AutoloaderException extends Exception{}

The above autoloader is a Singleton that includes classes and interfaces on demand via the SPL stack. If you've already grasped its driving logic, itís time (finally) to set up a script that shows the actual functionality of the earlier user service.

This script will be created in the following segment, so click on the link below and keep reading.



 
 
>>> 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: