Fluid.php

This software is experimental and diversionary. Only some features and concepts are illustrated by this overview page, and their implementation may change. Comments are invited.

©2009 Nigel Chapman.

Abstract

Fluid is a 'fluent' wrapper for PHP's array functions, giving them a chainable interface that works well with closures. It has been influenced considerably by Ruby and JQuery. It is designed for ease of use, in line with the UNIX philosophy of simple and reliable tools, which become powerful in combination. It is very new software, and you should expand the test suite to your satisfaction before using it commercially.

<?php echo Fluid::take(array('World!''Hello,'))->reverse()->join(' '); ?>
Hello, World!

Files

Laid out for Zend Framework, Fluid looks like this (click to view source).

Plus some documentation. Click here to Download the files (.tgz, 25K).

Examples

The following sample data will be used repeatedly.

<?php 

    $fibonacci 
Fluid::take(array(1235811)); 

    
$words Fluid::takeWords("The quick brown fox jumped over the lazy dog."); 

    
//  http://en.wikipedia.org/wiki/States_and_territories_of_Australia

    
$populationDensity Fluid::takeCsv
       
'"Australian Capital Territory","339900","2358","144.1"
        "Victoria","5205200","227146","22.9"
        "New South Wales","6889100","800642","8.6"
        "Tasmania","493300","68401","7.2"
        "Queensland","4182100","1730648","2.4"
        "South Australia","1584500","983482","1.6"
        "Western Australia","2105800","2529875","0.8"
        "Northern Territory","215000","1349129","0.2"'
); 

    
//  Some anonymous functions

    
$lowerCase =     create_function('$s''return strtolower($s);'); 
    
$stringLength =  create_function('$s''return strlen($s);'); 
    
$stringReverse create_function('$s''return strrev($s);'); 

    
//  And a simple 'person' object

    
class Person
    
{
        public function 
__construct($firstname$surname$age$postcode)
        {
            
$this->firstname $firstname;
            
$this->surname $surname
            
$this->age = (int)$age;
            
$this->postcode $postcode
        }

        public function 
firstLetter()
        {
            return 
substr($this->firstname01); 
        }

        public function 
ageBracket()
        {
            
$decade floor($this->age 10); 
            return (
$decade 10) . '-' . ((($decade 1) * 10) - 1); 
        }
    }

    
$people Fluid::take(array(
        new 
Person('Dean''Hendricksen'19'2010'),
        new 
Person('Derek''Grimmett'43'5023'),
        new 
Person('Monique''Depardieu'41'2830'),
        new 
Person('Dave''Jones'76'2230'),
        )); 

Basic numbers and strings

<?php 

    $f 
$fibonacci
    
$p $populationDensity->get('1');  //  2nd column
    
$a $populationDensity->get('2');  //  3rd column

    
echo Fluid::take(array(

        array(
""           'Minimum''Maximum''Average',     'Std. Dev.'), 
        array(
"Fibonacci"  $f->min(), $f->max(), $f->average(), $f->stddev()), 
        array(
"Population" $p->min(), $p->max(), $p->average(), $p->stddev()), 
        array(
"Area"       $a->min(), $a->max(), $a->average(), $a->stddev()), 

    ))->
htmlTable();

Minimum Maximum Average Std. Dev.
Fibonacci 1 11 5 3.5118845842842
Population 215000 6889100 2626862.5 2350283.2089652
Area 2358 2529875 961460.125 828014.07877666

Manipulating arrays

Arrays can be chopped up into smaller arrays in several ways:

<?php 

    
echo Fluid::take(array(
        
$words->first(), 
        
$words->first(5)->join(' ... '), 
        
$words->slice(33)->join(' ... '), 
        
$words->last(3)->join(' ... '), 
        
$words->random(), 
        
$words->random(3)->join(' ... '),  //  Reload
    
))->htmlList(); 

    echo 
$words->columns(3)->htmlTable(); 

The fox the
quick jumped lazy
brown over dog

Sorting arrays

Sorting by keys or attributes

<?php

    
echo $populationDensity->sort('0')->htmlTable(); 

Australian Capital Territory 339900 2358 144.1
New South Wales 6889100 800642 8.6
Northern Territory 215000 1349129 0.2
Queensland 4182100 1730648 2.4
South Australia 1584500 983482 1.6
Tasmania 493300 68401 7.2
Victoria 5205200 227146 22.9
Western Australia 2105800 2529875 0.8

Sorting by values

<?php

    
echo Fluid::take(array(

        array(
'ASCII Ascending',         $words->sort()->join(', ')), 
        array(
'ASCII Descending',        $words->sort()->reverse()->join(', ')), 
        array(
'Transform and sort',      $words->map($lowerCase)->sort()->join(', ')), 
        array(
'(and make unique)',       $words->map($lowerCase)->sort()->unique()->join(', ')), 
        array(
'Sort by function result'$words->sort($lowerCase)->join(', ')), 
        array(
'Multisort',               $words->sort(array($stringLength$lowerCase))->join(', ')), 

    ))->
htmlTable(); 

ASCII Ascending The, brown, dog, fox, jumped, lazy, over, quick, the
ASCII Descending the, quick, over, lazy, jumped, fox, dog, brown, The
Transform and sort brown, dog, fox, jumped, lazy, over, quick, the, the
(and make unique) brown, dog, fox, jumped, lazy, over, quick, the
Sort by function result brown, dog, fox, jumped, lazy, over, quick, The, the
Multisort The, dog, fox, the, lazy, over, brown, quick, jumped

The last two sorts above are examples of 'Schwartzian Transforms'; the list is sorted by the result of a mapping, but is not itself changed by that mapping. A good example is sorting sentences by the last word they contain:

The obligatory Schwartian example

<?php 

    
//  Excerpt from 'Epigrams on Programming' by Alan J. Perlis.
    //  http://www-pu.informatik.uni-tuebingen.de/users/klaeren/epigrams.html

    
$epigrams Fluid::takeLines(
       
"One man's constant is another man's variable.
        Functions delay binding: data structures induce binding. Moral: Structure data late in the programming process.
        Syntactic sugar causes cancer of the semi-colons.
        Every program is a part of some other program and rarely fits.
        If a program manipulates a large amount of data, it does so in a small number of ways."
); 

    
$lastWord create_function('$s''return end(split(" ", $s));'); 

    echo 
$epigrams->sort($lastWord)->htmlList(); 

Sorting tables

<?php

    
echo "<table>\n";
    foreach (
$people->collate(array('ageBracket'))->out() as $ageBracket => $peopleInBracket) {
        echo 
"<tr><th colspan=\"4\">$ageBracket</th></tr>\n";
        echo 
Fluid::take($peopleInBracket)->sort('-surname')->htmlTableRows(); 
    }
    echo 
"</table>\n";

10-19
Dean Hendricksen 19 2010
40-49
Derek Grimmett 43 5023
Monique Depardieu 41 2830
70-79
Dave Jones 76 2230
<?php

    
echo "<table>\n";
    foreach (
$people->collate(array('firstLetter'))->out() as $letter => $peopleStartignWith) {
        echo 
"<tr><th colspan=\"4\">$letter</th></tr>\n";
        echo 
Fluid::take($peopleStartignWith)->get(array('surname''firstname''age'))->sort('2')->htmlTableRows(); 
    }
    echo 
"</table>\n";

D
Hendricksen Dean 19
Grimmett Derek 43
Jones Dave 76
M
Depardieu Monique 41