Fluidics
- Requirements: PHP 5 (should work in 5.1.0, also tested in 5.2.3)
- License: GNU Lesser Public (enclosed)
- Status: In development - Run test.php if in doubt
Fluidics is a reaction to a couple of PHP annoyances, namely:
- Missing syntaxes for that require you to assign to a variable before being able to do what you really want
- Having to type lots of getters and setter all the time. Even if you if you have a way of typing them really quickly (and I do) they still pad out your code.
In addition to this page/file you might find the contents of test.php useful as a documentation source. If you're using Fluidics, have any suggestions etc. drop me an email!!
Function Reference
with()
mixed with(mixed $object)
with() is a stupidly simple function (no really, go and look at it's definition) that allows you to use a newly instantiated object without first having to assign it to a variable.
The solidic way:
$spec = new Spec(); $result = $spec->fulfilled();
The fluidic way:
$result = with(new Spec())->fulfilled();
index()
mixed index(array $array, string|int $key)
Used to get a single element from an array or, crucially, a function that returns an array.
The solidic way:
$pathInfo = pathinfo($path); $extension = $pathInfo['extension'];
The fluidic way:
$extension = index(pathinfo($path), 'extension');
The solidic way:
$vowels = array('a', 'e', 'i', 'o', 'u');
return $vowels[$index];The fluidic way:
return index(array('a', 'e', 'i', 'o', 'u'), $index);index() will trigger an error if $key is not defined inside $array, to prevent this see dindex().
Index can also be used to retrieve an element from a multi-dimensional array. This can be achieved by specifying $key as an array. The array of keys will be used each in turn to descend, however far, into the array a return an element.
Example:
function organic()
{
return array( // multi-dimensional return
'veg' => array(null),
'fruit' => array('grapefruit' => 5, 'apple' => 9)
);
}
$numApples = index(organic(), array('fruit', 'apple')); // 9dindex()
mixed dindex(array $array, string|int $key, mixed $default = null)
Short for "default index", this function behaves like index() but won't trigger an error if $key is undefined in $array, instead $default will be returned.
The solidic way:
if (!isset($raccoons[$name])) {
$raccoons[name] = 'unknown';
}
return $raccoons[$name];Bad practise:
return @$raccoons[$name];
The fluidic way:
return dindex($raccoons, $name, 'unknown');
If $name is defined in $raccoons then $raccoons[$name] will be returned, otherwise 'unknown' will be. No errors will be triggered.
Like index(), dindex() will handle multi-dimensional arrays if $key is provided as an array of keys. $default will be returned if a key that does not exist is encountered as dindex() descends into the array.
mindex()
mixed mindex($array, $keys, $preserve_keys = false)
m stands for multiple. You can use mindex() return many elements at once.
$array = array(1 => 'a', 'b', 'c', 'd', 'e', 'f');
mindex($array, array(1, 3, 6)); // array('a', 'c', 'f')By default mindex() will throw away any keys and start from zero again. To prevent this you may set the third parameter to true.
mindex($array, array(1, 3, 6), true); // array(1 => 'a', 'c', 'f')
Like index(), mindex() will trigger errors if you try to get an element at an undefined index.
array_intersect_key() (PHP 5.1 and greater) is similar but not quite the same as this and dmindex().
dmindex()
mixed dmindex($array, $keys, $preserve_keys = false, $default = null)
d and m still stand for the same things. This is dindex() and mindex() combined.
$array = array(1 => 'a', 'b', 'c', 'd', 'e', 'f');
dmindex($array, array(1, 3, 9), false, 'default'); // array('a', 'c', 'default')
dmindex($array, array(1, 3, 9), true); // array(1 => 'a', 3 => 'c', 9 => null)args()
array args()
Returns the arguments that the function in context was called with. Basically the same as func_get_args() only you don't have to assign it to a variable to use it first.
Example:
function foo()
{
return args();
}
foo(1, 2, 3); // array(1, 2, 3);accessor()
mixed accessor(object $obj, mixed &$property, array $args)
Used to implement an accessor method of a class. This function returns $property if $args is empty. Otherwise $obj is returned and $property it set to $args[0], by reference.
I always found that saying getFoo(), setFoo(), getBar() and setBar() a little monotonous. accessor() can be used to create a single method that combines setter and getter functionality.
Example:
class Square
{
private $size = null;
public function size() {
return accessor($this, $this->size, args());
}
public function halfSize() {
return $this->size / 2;
}
}
// Demonstration
$square = new Square();
// gets private property $size
$square->size(); // null
// sets private property $size and returns self
$square->size(5); // $square
// gets private property $size
$square->size(); // 5
$result = $square->halfSize(); // 2.5
// The fluidic way:
$result = with(new Square())->size(5)->half();So now we have a class with a single method size() that implements a fluent interface and can be used to both set and get the size property.
dump()
mixed dump(mixed $var, ...)
Performs a var_dump() and returns the variable being dumped afterwards.
Often often in test cases I find I want to get more information about a failure.
Scenario: This is failing. But why?
$this->assertTrue($obj->getSomeObj()->someOperation());
So I have to add this line:
var_dump($obj->getSomeObj());
If $obj->getSomeObj() has side-effects this could then affect the assertions below as well.
dump(), unlike var_dump(), which returns nothing, returns its parameter again. So to get more information I can just change the existing line like to this:
$this->assertTrue(dump($obj->getSomeObj()->someOperation()));
sdump()
string sdump(mixed $var)
Like var_dump() only the dump is returned instead of being echoed.
flu_error()
void flu_error($msg, $code, $back_offset = 1)
Often the real reason why a piece of code fails begins somewhere back in the call stack and not at the point where the failure is recognised. flu_error() allows you to trigger errors that point you to a file and line further back in the call stack: where the error originates. Use this to spare yourself and others the pain of endlessly inserting debug_print_backtrace() into code and grimacing at it's confusing output.
Example:
function gimmeFive($arg)
{
if ($arg != 5) {
flu_error('I expected a five!', E_USER_ERROR);
}
}
// error triggered will point you to this line:
gimmeFive(3);
// not the one inside gimmeFiveYou may use the third argument of flu_error() to seek further back into the stack.
lambda()
lambda lambda(string $args, string $code)
Use this just as you would create_function(). The test case illustrates the only significant difference
// Lambda should differ from create_function by returning the same var
// the 2nd param (lambda code) hasn't been re-evaluated
$a = lambda('$a, $b', 'return $a + $b;');
$b = lambda('$a, $b', 'return $a + $b;');
assert($a === $b);umap()
array umap(array $input, string $code)
Use this function to execute a piece of code on every element of an array and return the result.
Variables $v (for value) and $k (for key) are available for use in the code that gets executed.
Some examples:
// Works the same as array_keys
$array = array('a' => 1, 'b' => 2, 'c' => 3);
$keys = umap($array, 'return $k');
var_dump($keys === array_keys($array)); // bool(true)// Get all the method name as strings that appear in DOMDocument
$methods = with(new ReflectionClass('DOMDocument'))->getMethods();
$methodNames = umap($methods, 'return $v->getName()');The code you specify runs in it's own scope:
$x = 1000; // Undefined variable: x umap(array(1), 'return $v + $x'); // array(1)
The only way to get round this is to use $GLOBALS. :-(
More
There are additional functions in string.php that help out with some common irritations.