Monthly Archives: August 2011

Building a small microframework with PHP (Part 2). Command line interface

In my last post we spoke about building a small microframework with PHP. The main goal of this kind of framework was to be able to map urls to plain PHP classes and become those classes easily testeable with PHPUnit. Now we’re going to take a step forward. Sometimes we need to execute the script from command line, for example if we need to use them in a crontab file. OK. We can use curl and perform a simple http call to the webserver. But it’s pretty straightforward to create a command line interface (CLI) for our microframework. Zend Framework and Symfony has a great console tools. I’ve used Zend_Console_Getopt in a project and is really easy to use and well documented. But now we’re going to build a command line interface from scratch.

We are going to reuse a lot of code from the earlier post, because of that we are going to encapsulate the code in a class (DRY).

We will use the getopt function from PHP’s function set.

$sortOptions = "";
$sortOptions .= "c:";
$sortOptions .= "f:";
$sortOptions .= "v::";
$sortOptions .= "h::";

$options = getopt($sortOptions);

Then we need to take the paramaters from $GLOBALS['argv'] superglobal according with the options. I use the following hack to prepare $GLOBALS['argv']:

foreach( $options_array as $o => $a ) {
    while($k=array_search("-". $o. $a, $GLOBALS['argv'])) {
        if($k) {
            unset($GLOBALS['argv'][$k]);
        }
    }
    while($k=array_search("-" . $o, $GLOBALS['argv'])) {
        if($k) {
            unset($GLOBALS['argv'][$k]);
            unset($GLOBALS['argv'][$k+1]);
        }
    }
}
$GLOBALS['argv'] = array_merge($GLOBALS['argv']);

And now we get the params into $param_arr array.

$param_arr = array();
$lenght = count((array)$GLOBALS['argv']);
if ($lenght > 0) {
    for ($i = 1; $i < $lenght; $i++) {
        if (isset($GLOBALS['argv'][$i])) {
            list($paramName, $paramValue) = explode("=", $GLOBALS['argv'][$i], 2);
            $param_arr[$paramName] = $paramValue;
        }
    }
}

Now we can get className and functionName:

$className    = !array_key_exists('c', $options) ?: $options['c'];
$functionName = !array_key_exists('f', $options) ?: $options['f'];

We add a “usage” parameter:

if (array_key_exists('h', $options)) {
     $usage = <<<USAGE
Usage: cli [options] [-c] <class> [-f] <function> [args...]

Options:
-h Print this help
-v verbose mode
\n
USAGE;
    echo $usage;
    exit;
}

Now we can invoke the function with call_user_func_array

return call_user_func_array(array($className, $functionName), $this->realParams);

As you can see, instead of using $param_arr as parameters array, We need to create an extra $realParams array. The aim of this realParams arrays is to use call_user_func_array with named parameters. In getRealParams function we use reflection to see what are the real parameters of our function and use only those parameters form in the correct order instead. With this trick we will allow to the user to use the parameters in the his desired order, and without forcing to use the real order of our function.

    private function getRealParams($params)
    {
        $realParams = array();
        $class = new ReflectionClass(new $this->className);
        $reflect = $class->getMethod($this->functionName);

        foreach ($reflect->getParameters() as $i => $param) {
            $pname = $param->getName();
            if ($param->isPassedByReference()) {
                /// @todo shall we raise some warning?
            }
            if (array_key_exists($pname, $params)) {
                $realParams[] = $params[$pname];
            } else if ($param->isDefaultValueAvailable()) {
                $realParams[] = $param->getDefaultValue();
            } else {
                throw new Exception("{$this->className}::{$this->functionName}() param: missing param: {$pname}");
            }
        }
        return $realParams;
    }

And now we can use our microframework from the command line:

./cli -c 'Demo\Foo' -f hello
Hello

./cli -c Demo\\Foo -f getUsers
["Gonzalo","Peter"]

./cli -c Demo\\Foo -f helloName name=Gonzalo surname=Ayuso
Hello Gonzalo Ayuso

Full code on github

Building a small microframework with PHP

Nowadays microframewors are very popular. Since Blake Mizerany created Sinatra (Ruby), we have a lot of Sinatra clones in PHP world. Probably the most famous (and a really good one) is Silex. But we also have several ones, such as Limonade, GluePHP and Slim. Those frameworks are similar. We define routes and we connect those routes to callbacks:

For example:

‘/hello/{name}’ => function ($name) {return “Hello $name”;}

Those microframeworks use the new PHP 5.3 callback features. It’s easy to build prototypes with those frameworks. I’ve used silex for a small prototype and I’m really happy with it. But I have a little problem. Each time I need to create a new route I need to create the route and create the callback. The business logic is inside the callback, but I need to tell to the framework where is it with the router. That’s means code de callback and write the router. This way of work has advantages. You can change the routes without changing the business logic. I feel comfortable with it in small projects, but when it scales it’s difficult to manage (at least for me). Symfony2 has a great way to create routes, with inheritance, catching and things like that, but sometimes I dont’t feel confortable with it. Because of that I have done this small microframework experiment. The idea is drop the router and create it depending on the filesystem. The first idea was inside this postit:

Yes I now. If I want to change the class inside the filesystem, I need to change the urls. As an experiment, I’ve created a small microframework. The idea the following one:

  • .htaccess to redirect every request to index.php
  • a set of classes (plain php classes)
  • index.php will invoke the required class’ function
  • after invoking the required function index.php will convert the output to the format selected

Basically index.php will follow the following script:

setUpAutoload();
list($className, $functionName, $format, $params) = decodeUri(getUri());
$realParams = getRealParams($className, $functionName, $params);
echo format($format, call_user_func_array(array($className, $functionName), $realParams));

Here you have the full index.php code:

function call_user_func_named($className, $obj, $function, $params)
{
    $class = new ReflectionClass($obj);
    $reflect = $class->getMethod($function);

    $realParams = array();
    foreach ($reflect->getParameters() as $i => $param) {
        $pname = $param->getName();
        if ($param->isPassedByReference()) {
            /// @todo shall we raise some warning?
        }
        if (array_key_exists($pname, $params)) {
            $realParams[] = $params[$pname];
        } else if ($param->isDefaultValueAvailable()) {
            $realParams[] = $param->getDefaultValue();
        } else {
            throw new Exception("{$className}::{$function}() param: missing param: {$pname}");
        }
    }

    return call_user_func_array(array(new $obj, $function), $realParams);
}

function decodeUri($uri)
{
    $conf = $params = array();
    $functionName = $format = null;

    $parsedUrl = parse_url($uri);
    $path = $parsedUrl['path'];
    if (isset($parsedUrl['query'])) {
        $query = $parsedUrl['query'];
        $params = array();
        $pairs = explode('&', $query);
        foreach ($pairs as $pair) {
            if (trim($pair) == '') {
                continue;
            }
            list($key, $value) = explode('=', $pair);
            $params[$key] = urldecode($value);
        }
    }
    $arr = explode('/', $path);

    for ($i = 0; $i < count($arr); $i++) {
        $elem = $arr[$i];
        if (strpos($elem, '.') !== false) {
            list($functionName, $format) = explode(".", $elem);
            continue;
        } else {
            if ($elem != '') $conf[] = ucfirst($elem);
        }
    }

    $className = implode('\\', $conf);
    return array($className, $functionName, $format, $params);
}

function format($format, $out)
{
    switch ($format) {
        case 'json':
            header('Cache-Control: no-cache, must-revalidate');
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
            header('Content-type: application/json');
            return json_encode($out);
        case 'html':
        case 'htm':
            header('Cache-Control: no-cache, must-revalidate');
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
            header('Content-type: Content-Type: text/html');
            return (string)$out;
        case 'txt':
        case 'ajax':
            header('Content-type: text/plain; charset=utf-8');
            return (string)$out;
        case 'css':
            header('Content-type: text/css');
            return (string)$out;
        case 'js':
            header('Content-type: application/javascript');
            return (string)$out;
        case 'jsonp':
            $cbk = filter_input(INPUT_GET, '_cbk', FILTER_SANITIZE_STRING);
            if ($cbk == '') {
                $cbk = 'cbk';
            }

            header('Content-type: text/javascript; charset=utf-8');
            return "{$cbk}(" . json_encode($out) . ");";
        default:
            throw new Exception("Undefined format");
    }
}

function getRealParams($className, $functionName, $params)
{
    $realParams = array();
    $class = new \ReflectionClass(new $className);
    $reflect = $class->getMethod($functionName);

    foreach ($reflect->getParameters() as $i => $param) {
        $pname = $param->getName();
        if ($param->isPassedByReference()) {
            /// @todo shall we raise some warning?
        }
        if (array_key_exists($pname, $params)) {
            $realParams[] = $params[$pname];
        } else if ($param->isDefaultValueAvailable()) {
            $realParams[] = $param->getDefaultValue();
        } else {
            throw new Exception("{$className}::{$functionName}() param: missing param: {$pname}");
        }
    }
    return $realParams;
}

function setUpAutoload()
{
    spl_autoload_register(function ($class)
        {
            $class = str_replace('\\', '/', $class) . '.php';
            if (is_file($class)) {
                require_once($class);
            } else {
                throw new Exception("{$class} does not exists");
            }
        }
    );
}

function getUri()
{
    $requestUri = $_SERVER['REQUEST_URI'];
    $scriptName = $_SERVER['SCRIPT_NAME'];

    if (dirname($scriptName) == '/') {
        $uri = $requestUri;
        return $uri;
    } else {
        $uri = str_replace(dirname($scriptName), null, $requestUri);
        return $uri;
    }
}

An example of the plain php classes with the business logic:

namespace Demo;

class Foo
{
    public function hello()
    {
        return "Hello";
    }

    public function helloName($name)
    {
        return "Hello " . $name;
    }

    public function getUsers()
    {
        return array('Gonzalo', 'Peter', );
    }
}

This class is easily testable with PHPUnit.

Normally I use this kind of framework to get json and jsonp. It’s pretty straightforward to get json:

http://localhost/demo/foo/getUsers.json
["Gonzalo","Peter"]

http://localhost/demo/foo/getUsers.jsonp

cbk(["Gonzalo","Peter"]);

This is a very small approach of what I have in mind, coded with a few lines to show the concept. I’m working in some more advanced features such as twig integration, security, and things like that. The idea is combine the plain PHP classes with annotations (with Addendum). Imagine a class like that:

Here @Render() annotation tells to the framework to use a twig template.

// http://localhost/tdl/index.html

class Tdl
{
    /**
     * @Render()
     * @return array
     */
    public function index()
    {
        return array(
            'title'       => 'Simple ToDo List',
            'description' => 'Simple ToDo List',
            'author'      => 'Gonzalo',
        );
    }
}

And here will output a javascript file using assetic library

// http://localhost/tdl/js/js.js

namespace Tdl;

use Assetic\Asset\AssetCollection;
use Assetic\Asset\FileAsset;
use Assetic\Filter\FilterInterface;

class Js
{
    public function js()
    {
        $js = new AssetCollection(array(
            new FileAsset(MVC_PATH . '/V/Tdl/Js/nf.js'),
            new FileAsset(MVC_PATH . '/V/Tdl/Js/main.js'),
        ));

        return  $js->dump();
    }
}

Sometimes I think Symfony2 has all this features and developing this framework is a waste of time. Probably, but it’s cool to code it. Also it’s very easy and fast for me build prototypes. What do you think?

Initial commit here (the code used in this post).
Full code on github

Checking the performance reading arrays with PHP

Reading last Fabien Potencier’s post I see something interesting: “People like micro-optimizations. They are easy to understand, easy to apply… and useless“. It’s true. We don’t need to obsess with small micro-optimizations. As someone said in a comment “developer time is more precious than processor time“. It’s true again. But normally our code is coded once and executed thousands of times, and we must keep in mind that CPU time many times means money. We need to balance it (as always). But, WTH. I like micro-optimizations, and here comes another one: Checking the access to arrays with PHP.

$limit = 1000000;
$randomKey = rand(0, $limit);

// we create a huge array
$arr = array();
for($i=0; $i<=$limit; $i++) {
    $arr[$i] = $i;
}

error_reporting(-1);
$time = microtime(TRUE);
$mem = memory_get_usage();

$value = $arr[$randomKey];
for($i=0; $i<=$limit; $i++) {
    echo $value;
}

print_r(array('memory' => (memory_get_usage() - $mem) / (1024 * 1024), 'microtime' => microtime(TRUE) - $time));

with this first example we will loop over a big for statement and we are going to retrieve the value of an array.

[memory] => 5.6837158203125 [microtime] => 0.32066202163696

Now we’re going to do the same, but getting the value of the array inside the loop:

for($i=0; $i<=$limit; $i++) {
    $value = $arr[$randomKey];
    echo $value;
}

[memory] => 5.6837158203125 [microtime] => 0.35844492912292

and now without creatin the extra variable $value

for($i=0; $i<=$limit; $i++) {
    echo $arr[$randomKey];
}

[memory] => 5.683666229248 [microtime] => 0.35710000991821

Conclusion

As we can see the memory usage is almost the same, and the time is almost the same too. Obviously fetching the value of the array outside the loop is faster than doing inside the loop. But we must take into account that we’re working with big arrays. With small ones those times are very similar. This time we don’t have any significant outcome. Both methods have the same behaviour. Maybe it can be obvious, but I wanted to check it out.

Runtime Classes. A experiment with PHP and Object Oriented Programming

Last week I was thinking about creation of a new type of classes. PHP classes but created dynamically at run time. When this idea was running through my head I read the following article and I wanted to write something similar. Warning: Probably that it is something totally useless, but I wanted to create a working prototype (and it was fun to do it ;) ). Let’s start:

We are going to crate something like this:

class Human
{
  private $name;
  function __construct($name)
  {
    $this->name = $name;
  }

  function hello()
  {
    return "{$this->name} says hello";
  }
}

$gonzalo = new Human('Gonzalo');
$peter = new Human('Peter');

echo $gonzalo->hello(); // outputs: Gonzalo says hello
echo $peter->hello(); // outputs: Peter says hello

but without using class statement, adding the constructor and hello method dinamically.

  function testSimpleUsage()
  {
    $human = HClass::define()
      ->fct(HClass::__construct, function($self, $name) {$self->name = $name;})
      ->fct('hello', function($self) {
          return "{$self->name} says hello";
        });

    $gonzalo = $human->create('Gonzalo');
    $peter = $human->create('Peter');

    $this->assertEquals("Gonzalo says hello", $gonzalo->hello());
    $this->assertEquals("Peter says hello", $peter->hello());
  }

I also want to test undefinded functions with an exception:

  function testCallingUndefinedFunctions()
  {
    $human = HClass::define()
      ->fct(HClass::__construct, function($self, $name) {$self->name = $name;})
      ->fct('hello', function($self) {
              return "{$self->name} says hello";
            });

    $gonzalo = $human->create('Gonzalo');
    $this->setExpectedException('Exception', "ERROR Method 'goodbye' does not exits");
    $gonzalo->goodbye();
  }

And simple inheritance too

  function testInheritance()
  {
    $human = HClass::define()
      ->fct(HClass::__construct, function($self, $name) {$self->name = $name;})
      ->fct('hello', function($self) {
              return "{$self->name} says hello";
            });

    $shyHuman = HClass::define($human)
      ->fct('hello', function($self) {
              return "{$self->name} is shy and don't says hello";
            });

    $gonzalo = $human->create('Gonzalo');
    $peter = $shyHuman->create('Peter');

    $this->assertEquals("Gonzalo says hello", $gonzalo->hello());
    $this->assertEquals("Peter is shy and don't says hello", $peter->hello());
  }

Now we are going to create dinamically functions:

  function testDinamicallyFunctionCreation()
  {
    $human = HClass::define()
      ->fct(HClass::__construct, function($self, $name) {$self->name = $name;})
      ->fct('hello', function($self) {
              return "{$self->name} says hello";
            });

    $gonzalo = $human->create('Gonzalo');
    $this->assertEquals("Gonzalo says hello", $gonzalo->hello());

    try {
      $gonzalo->goodbye();
    } catch (Exception $e) {
      $this->assertEquals("ERROR Method 'goodbye' does not exits", $e->getMessage());
    }

    $human->fct('goodbye', function($self) {
              return "{$self->name} says goodbye";
            });

    $this->assertEquals("Gonzalo says goodbye", $gonzalo->goodbye());
  }

And that’s it. It works. probably with PHP5.4 we can drop the “$self” variable. It’s an ugly trick to pass the real instance of the class to the callback, thanks to the “Added closure $this support back” feature added in the new version of PHP. But at least now we need to it.

And now another turn the screw. Let’s try to create the FizzBuzz kata with those “Runtime Classes”. I will create two versions of FizzBuzz. Here you can see my implementation of both versions with “standard” PHP. Whith a simple class, and another one with Two classes and Dependency Injection. Now using the experiment:

  function testFizzBuzz()
  {
    $fizzBuzz = HClass::define()
      ->fct('run', function($self, $elems = 100) {
          list($fizz, $buzz) = array('Fizz', 'Buzz');
          return array_map(function ($element) use ($fizz, $buzz) {
              $out = array();
              if ($element % 3 == 0 || strpos((string) $element, '3') !== false ) {
                $out[] = $fizz;
              }
              if ($element % 5 == 0 || strpos((string) $element, '5') !== false ) {
                $out[] = $buzz;
              }
              return (count($out) > 0) ? implode('', $out) : $element;
            }, range(0, $elems-1));
        });
    $fizzBuzz = $fizzBuzz->create();
    $arr = $fizzBuzz->run();

    $this->assertEquals(count($arr), 100);
    $this->assertEquals($arr[1],  1);
    $this->assertEquals($arr[3],  'Fizz');
    $this->assertEquals($arr[4],  4);
    $this->assertEquals($arr[5],  'Buzz');
    $this->assertEquals($arr[6],  'Fizz');
    $this->assertEquals($arr[20], 'Buzz');
    $this->assertEquals($arr[13], 'Fizz');
    $this->assertEquals($arr[15], 'FizzBuzz');
    $this->assertEquals($arr[53], 'FizzBuzz');
  }
  function testAnotherFizzBuzzImplementationWithDependencyInjection()
  {
    $fizzBuzz = HClass::define();
    $fizzBuzz->fct(HClass::__construct, function($self, $fizzBuzzElement) {
         $self->fizzBuzzElement = $fizzBuzzElement;
       });
    $fizzBuzz->fct('run', function($self, $elems = 100) {
         $out = array();
         foreach (range(1, $elems) as $elem) {
           $out[$elem] =  $self->fizzBuzzElement->render($elem);
         }
         return $out;
       });
    
    $fizzBuzzElement = HClass::define()
      ->fct('render', function($self, $element) {
          list($fizz, $buzz) = array('Fizz', 'Buzz');
          $out = array();
          if ($element % 3 == 0 || strpos((string) $element, '3') !== false ) {
            $out[] = $fizz;
          }

          if ($element % 5 == 0 || strpos((string) $element, '5') !== false ) {
            $out[] = $buzz;
          }
          return (count($out) > 0) ? implode('', $out) : $element;
      });

    $fbe = $fizzBuzzElement->create();

    $this->assertEquals($fbe->render(1),  1);

    $this->assertEquals($fbe->render(2),  2);
    $this->assertEquals($fbe->render(3),  'Fizz');
    $this->assertEquals($fbe->render(4),  4);
    $this->assertEquals($fbe->render(5),  'Buzz');
    $this->assertEquals($fbe->render(6),  'Fizz');
    $this->assertEquals($fbe->render(20), 'Buzz');
    $this->assertEquals($fbe->render(13), 'Fizz');
    $this->assertEquals($fbe->render(15), 'FizzBuzz');
    $this->assertEquals($fbe->render(53), 'FizzBuzz');

    $fb = $fizzBuzz->create($fbe);
    $arr = $fb->run();

    $this->assertEquals(count($arr), 100);
    $this->assertEquals($arr[1],  1);
    $this->assertEquals($arr[3],  'Fizz');
    $this->assertEquals($arr[4],  4);
    $this->assertEquals($arr[5],  'Buzz');
    $this->assertEquals($arr[6],  'Fizz');
    $this->assertEquals($arr[20], 'Buzz');
    $this->assertEquals($arr[13], 'Fizz');
    $this->assertEquals($arr[15], 'FizzBuzz');
    $this->assertEquals($arr[53], 'FizzBuzz');
  }

And that’s all. As I said before probably this “Hybrid Classes” or “Runtime Classes” (I don’t know how to name them) are totally useless, but it’s fun to do it.

phpunit HclassTest.php 
PHPUnit 3.4.5 by Sebastian Bergmann.

......

Time: 0 seconds, Memory: 5.00Mb

OK (6 tests, 39 assertions)

Full code on github

Building a client for a REST API with PHP.

Today we’re going to create a library to use a simple RESTfull API for a great project called Gzaas. Don’t you know what the hell is Gzaas? Gzaas is simple idea idea of a friend of mine (hi @ojoven!). A simple project that creates cool mesages on full screen. Then you can share the link in twitter, facebook and things like that. Yes. I now when I explain it, the first word that appear in our minds is WTF, but it’s cool, really cool.

Ok. The API is a simple RESTfull API, so we can use it with a simple curl interface. A few lines of PHP and it will run smoothly. But Gzaas is cool so we’re going to create a cool interface too. This days I’m involved into TDD world, so we’re going to create the API wrapper using TDD. Let’s start.

The first version of Gzaas API is a very simple one. It allow to create new messages, and we also can list the whole set of styles, patterns and fonts availables. The idea is build something as modular as we can. Problably (I hope so) Gzaas will include new features in a future, so we don’t want to build a monolitc library. We are going to start with fonts. As we can see in documentation we need to perform a GET request to get the full list of available fonts. There’s an important parameter (nowFeatured) to show only the featured fonts (the cool ones).

use Gzaas\Api;
$fonts = Api\Fonts::factory()->getAll(Api::FEATURED);

So we are going to crate a simple test to test our font API.

$this->assertTrue(count($fonts) > 0);

Whith this test we’re going to test fonts, but we also can test styles and patterns.

    public function testFonts()
    {
        $fonts = Api\Fonts::factory()->getAll(Api::FEATURED);
        $this->assertTrue(count($fonts) > 0);
    }

    public function testStyles()
    {
        $styles = Api\Styles::factory()->getAll(Api::FEATURED);
        $this->assertTrue(count($styles) > 0);
    }

    public function testPatterns()
    {
        $patterns = Api\Patterns::factory()->getAll(Api::FEATURED);
        $this->assertTrue(count($patterns) > 0);
    }

Ok now we are going to test the creation of a gzaas. We will use a random font, style and pattern:

$font    = array_rand((array) Api\Fonts::factory()->getAll(Api::FEATURED));
$style   = array_rand((array) Api\Styles::factory()->getAll(Api::FEATURED));
$pattern = array_rand((array) Api\Patterns::factory()->getAll(Api::FEATURED));

Let’s go:

$gzaas = new Api();
$url = $gzaas->setApiKey('mySuperSecretApiKey') // Get one valid at http://gzaas.com/project/api-embed/api-key
    ->setFont($font)
    ->setBackPattern($pattern)
    ->setStyle($style)
    ->setColor('444444')
    ->setBackcolor('fcfcee')
    ->setShadows('1px 0 2px #ccc')
    ->setVisibility(0)
    ->setLauncher("testin gzaas API");

As we can see our library has a fluid interface (I like fluid interface). It’s easy to implement. We only need to return the instance of the object (return $this;) in each setter function.

Gzaas API returns the url of the created gzaas when success, so $url variable must be different than empty string. Let’s test it:

$this->assertTrue($url != '');

To use this library we need to include the following files:

require_once __DIR__ . '/Api/ApiInterface.php'; 
require_once __DIR__ . '/Api/Network.php'; 
require_once __DIR__ . '/Api/ApiAbstract.php'; 
require_once __DIR__ . '/Api/Fonts.php'; 
require_once __DIR__ . '/Api/Patterns.php'; 
require_once __DIR__ . '/Api/Styles.php'; 
require_once __DIR__ . '/Api.php';

because of that there’s a simple bootstrap.php file to include all files. But we’re going to take a step forward. We’re going to create phar archive with the whole library inside. The creation of phar archive is very simple. We need a index.php file with the bootstrap (it must end with a __HALT_COMPILER();)

include dirname(__FILE__) . '/Api/ApiInterface.php';
include dirname(__FILE__) . '/Api/Network.php';
include dirname(__FILE__) . '/Api/ApiAbstract.php';
include dirname(__FILE__) . '/Api.php';
include dirname(__FILE__) . '/Api/Fonts.php';
include dirname(__FILE__) . '/Api/Patterns.php';
include dirname(__FILE__) . '/Api/Styles.php';

__HALT_COMPILER();

and the program buildPhar will create our phar file:

#!/usr/bin/env php
buildFromDirectory($location);

And that’s all. Now we can use the bootstrap.php file to include the library or we can also include the phar file:

include 'Gzaas/Gzaas.phar';

You can fork the code at github here. Feel free to browse the code and tell us what do you think?

Follow

Get every new post delivered to your Inbox.

Join 973 other followers