jgswift / qtil
PHP 5.5+ utility library
Requires
- php: >=5.5
- jgswift/restructr: 0.1.*
Requires (Dev)
- phpunit/phpunit: 3.7.*
- satooshi/php-coveralls: dev-master
This package is not auto-updated.
Last update: 2024-12-21 16:25:50 UTC
README
PHP 5.5+ utility library
Description
This package contains a variety of utilities to assist in development and reduce boilerplate.
Installation
Install via cli using composer:
php composer.phar require jgswift/qtil:0.1.*
Install via composer.json using composer:
{ "require": { "jgswift/qtil": "0.1.*" } }
Dependency
- php 5.5+
- jgswift/restructr domain component foundation
Usage
ArrayAccess
The following is an ArrayAccess minimal example
<?php class Foo implements \ArrayAccess, \Countable, \IteratorAggregate { use qtil\ArrayAccess, qtil\Countable, qtil\IteratorAggregate; } $foo = new Foo; $foo['bar'] = 'baz'; var_dump($foo['bar']); // returns "baz"
ObjectAccess
Much like ArrayAccess, ObjectAccess is available for conventional object magic..
While the following example appears to be default object behavior, all accessors and mutators are handled through magic and properties are stored locally in an array
<?php class Foo { use qtil\ObjectAccess; } $foo = new Foo; $foo->bar = 'baz'; var_dump($foo->bar); // returns "baz"
JSONAccess
The JSONAccess trait provides integrated JSON serialization and may be applied to both ObjectAccess and ArrayAccess objects.
<?php class Foo { use qtil\ObjectAccess, qtil\JSONAccess; } $foo = new Foo; $foo->bar = 'baz'; $json_string = $foo->toJSON(); $foo2 = new Foo; $foo2->fromJSON($json_string); var_dump($foo2->bar); // returns "baz"
Serializable
Normal object serialization is also available using the Serializable interface/trait combination. Regular serialization is also available to both ArrayAccess and ObjectAccess.
<?php class Foo implements \Serializable { use qtil\ObjectAccess, qtil\Serializable; } $foo = new Foo; $foo->bar = 'baz'; $serial_string = serialize($foo); $foo2 = unserialize($serial_string); var_dump($foo2->bar); // returns "baz"
Iterator
Qtil provides standard Iterator and IteratorAggregate implementations through the traits names Iterator and IteratorAggregate respectively.
<?php class Foo { use qtil\ObjectAccess, qtil\Iterator; } $foo = new Foo; $foo->bar = 'baz'; $foo->baz = 'rus'; foreach($foo as $name => $value) { var_dump($name,$value); // returns bar => baz, then baz => rus }
IteratorAggregate
<?php class Foo { use qtil\ObjectAccess, qtil\IteratorAggregate; } $foo = new Foo; $foo->bar = 'baz'; $foo->baz = 'rus'; foreach($foo as $name => $value) { var_dump($name,$value); // returns bar => baz, then baz => rus }
IteratorAggregate Custom Iterator
The iterator aggregate trait provides a convenience property to specify the iterator manually. By default, ArrayIterator is used.
class Foo { use qtil\ObjectAccess, qtil\IteratorAggregate; public static $ITERATOR_CLASS = 'FooIterator'; } class FooIterator implements \Iterator { function current() { /* ... */ } function key() { /* ... */ } function next() { /* ... */ } function rewind() { /* ... */ } function valid() { /* ... */ } } $foo = new Foo; foreach($foo as $value) { // iterates over foo using fooiterator }
Generator
A generator function may be specified to easily customize the iteration process without
requiring a custom Iterator
.
class Foo { use qtil\ObjectAccess, qtil\Generator; } $foo = new Foo([ 'bob', 'sam', 'jim' ]); $foo->setGenerator(function($item) { return $item; }); $gen = $foo->getGenerator(); foreach($gen as $item) { // 'bob' , 'sam' , 'jim' }
Identifier
Qtil contains a small utility to easily customize how objects are identified.
There are some default schemes for identifying objects that ensures individual object instances are identified respectively. You can use this functionality instead of spl_object_hash to ensure identifier uniqueness. Alternatively, a number of built-in schemes are available.
The following is the minimal example, using the default scheme
<?php class Foo { } $foo = new Foo(); $id = qtil\Identifier::identify($foo); // Returns an unique hash
With a minor change, you can encapsulate the identification behavior in your own class
class Foo { function getID() { return qtil\Identifier::identify($this); } } $foo = new Foo(); $id = $foo->getID(); // Returns an unique hash
Schemes
Alternatively, qtil provides a number of built-in schemes using a variety of ways to determine how to identify an object.
class Foo { function getID() { return qtil\Identifier::identify($this); } function getUniqueID() { return 1; } } qtil\Identifier::addScheme( new qtil\Identifier\Scheme\MethodScheme('getUniqueID') ); $foo = new Foo(); $id = $foo->getID(); // Returns 1
You may provide a custom callback method for most schemes
class Foo { function getID() { return qtil\Identifier::identify($this); } } qtil\Identifier::addScheme( new qtil\Identifier\Scheme\ClassScheme('Foo',function() { return 1; }) ); $foo = new Foo(); $id = $foo->getID(); // Returns 1
Factory
Object creation done by Reflection and arguments validated against constructor signature
A qtil\Exception is thrown is the given arguments do not match the class constructor
class User { /* ... */ } class MyUserFactory { use qtil\Factory; } $factory = new MyUserFactory; $user = $factory->make('User'); var_dump(get_class($user)); // 'User'
Proxy
A simple magic mediator.
Mediates an object instance through locally-scoped magic methods, namely __get, __set, __unset, __isset, and __call
class MyUserProxy { use qtil\Proxy; } class User { /* ... */ function sayHello() { return 'hello'; } } $user = new User; $proxy = new MyUserProxy(); $proxy->setSubject($user); $message = $proxy->sayHello(); var_dump($message); // 'hello'
Executable (Command)
This simple trait makes an object a callable and exposes the call through the execute method. The execute method may have any arguments and does not enforce any particular method signature.
class MyBinarySwitch { use qtil\Executable; function execute($start) { if($start) { return false; } return true; } } $switch = new MyBinarySwitch(); $result = $switch(false); // starts off var_dump($result); // ends on $result = $switch(true); // starts on var_dump($result); // ends off
Method Chaining
The chaining mechanism outlined below favors convention over configuration. Chainable methods are populated by all of the classes that are direct children of one or more namespaces. The namespaces are customizable but the default is a single namespace that matches the class signature of the chained class
class Query { use qtil\Chain; } // a namespace with the same signature as the class must be created // or alternatively the namespaces may be configured manually namespace Query { class Select { function __construct() { /* Specify relevant fields */ } } class From { function __construct() { /* Choose a source */ } } } namespace OtherQueryTypes { class Within { function __construct() { /* Specify constraints */ } } } // create a query using above chain classes $query = new Query; $query->select()->from(); var_dump(count($query->getLinks())); // 2 // this namespace extension will only extend this individual query instance $query->addNamespace("OtherQueryTypes"); $query->within(); var_dump(count($query->getLinks())); // 3 // add a second namespace globally to extend every instantiated object of this type. qtil\Chain\ClassRegistry::addNamespace('Query','OtherQueryTypes');
Note: any traits that use magic methods such as __get, __set, etc. are not compatible with eachother unless you provide a custom implementation to manually route duplicate methods. See the php traits documentation, specifically the insteadof operator.