chain/core

_Chain_ is freedom.

dev-master 2015-03-05 00:36 UTC

This package is not auto-updated.

Last update: 2024-05-25 14:52:52 UTC


README

Chain ###_Chain_ is freedom. _Chain_ is a library designed to optimize linear processing. ####In a nutshell _Chain_ originated from the observation that most modern applications follow a linear request/response pattern, with RESTful APIs leading the way.
_Chain_ aims at making such applications easy to code, test, debug, and maintain.

In the _Chain_ environment, each step of a program is a _Link_. A _Link_ is a class with a single EXE() function, designed to accomplish a single task.

In the spirit of functional programming, the goal is to reuse as much code as possible, hopefully making the design of a new application as simple as chaining links together.

In true composite fashion, a _Chain_ is also a _Link_, which makes it easy to build intermediate components.

####The I_O visitor Schema
The I_O visitor acts like a signal running through the _Chain_.

To achieve this goal, a _Link_'s EXE() method is set to receive an Input/Output visitor, or I_O visitor, and return it after applying a change to the data stored in its memory.

Think of the I_O object as a bag. Upon entering a _Link_, the content of the I_O object is emptied inside the EXE() method. The method uses these ingredients, and puts the resulting product in the bag.

The _Chain_ takes care of passing the I_O object from one _Link_ to the next, unless a _Link_ wishes to break the _Chain_ by setting its _X_() method to return TRUE.

At the end of the _Chain_, the I_O visitor contains the final result.

####Example Let's create a simple _Chain_ destined to format a string.

#####Install

$ composer require chain/core

#####Import the string library

$ composer require chain/string

Of course, installing chain/string directly would have imported chain/core automatically. The extra step was added for clarity.

#####Create an I_O object

// This example assumes we're in the _Chain_ namespace for clarity.
$IO = new IO('   tHis   sTRinG    IS   a meSS!    ');

#####Create the _Chain_

$chain = new Chain();
$chain->ADD(new String\_Whitespace_())
      ->ADD(new String\_Lowercase_());

#####Excecute

$chain->EXE($IO);

#####Result

$result = $IO->I_(Type::STRING); // $result = 'this string is a mess!'

####Dependency injection Evidently, _Chain_ is better served in a dependency injection context, within Symfony for instance.

Complex services can be created with a _Chain_ made of basic _Links_, and injected in your controllers, or classes.

In the future, we may build an entire framework with _Chain_, but we're going to need a much larger _Link_ library to achieve this goal. ####Inside a _Link_ Here's an example EXE() method inside a _Link_:

// Division
public function EXE(I_O $IO){
    $numerator = $IO->I_(Type::NUMBER);
    $denominator = $IO->I_(Type::NUMBER);
    return $IO->_O($numerator/$denominator);
}

#####Input Input variables are retrieved using the method I_($type, $optional=false). Each time the method is called, the next variable is retrieved.

The variables requested from the I_O visitor must be in the right order, and of the right type. Requesting a variable that doesn't exist, or that is of the wrong type, triggers an exception.

For this reason, the I_O visitor is not iterable. A valid type constant or class FQCN must be provided with each I_() call.

A second boolean argument can be provided when calling I_() to indicate that the requested I_O variable is optional.

This design effectively enforces type safety, palliating one of PHP's most criticized shortcoming.

However, in a production environment, where a _Chain_ has been properly tested, the internal type checking can be bypassed for a performance uptick:

$IO = new IO('foo');
$IO->prod(true);

All valid type constants are listed in the static type class.

An I/O contract should be included in the PHP doc of every _Link_'s EXE() method:

/**
 * Method action.
 *
 * Description.
 *
 * I/O contract
 * ------------
 * <pre>
 * I    string      Optional description.
 *      ...         as many inputs as needed.
 * O    number      Optional description.
 *      ...         as many outputs as needed.
 * X    yes/no      Breaks the chain if ...
 * </pre>
 */
public function EXE(I_O $IO);

#####Output The output of the I_O visitor is set by calling the _O() method, with an unlimited amount of arguments.

Calling this method effectively erases the internal memory of the I_O visitor, replacing it with each value that is passed as an argument of the _O() method.

These new values will be returned in the next _Link_, with each call to the I_() method:

$IO->_O('foo', 56, ['bar', 'baz'], $object);
// In the next link:
$IO->I_(Type:STRING); // Returns 'foo'
$IO->I_(Type:NUMBER); // Returns 56
$IO->I_(Type:MULTI); // Returns array('bar', 'baz)
$IO->I_('MyApp\MyClass'); // Returns the MyApp\MyClass object

After updating the I_O visitor's internal state, the _O() method returns the visitor itself, which makes the following shortcut possible:

public function EXE(I_O $IO)
{
    return $IO->_O('foo');
}

Of course, PHP passes objects by reference, which suggests it's unnecessary to return the I_O object in a _Chain_ execution. However, it is a requirement of the _Link_ interface for clarity, and to make the following shortcut possible when manipulating a _Chain_:

$result = $chain->EXE($IO)
                ->I_(Type:STRING);

####In an ideal world If we imagine a _Link_ library that is large enough to cover most application needs, we could easily port the entire library in many languages, including assembly, and make it possible to design an application in a language agnostic manner, using a graphical interface.

Such solutions will be widely used in the future, to address the current explosion of programming languages.