stdphp
Standard library for php.
php
is not my primary language, but when I use it occasionally, I always miss a consistent standard library. Therefore I've created this one for my needs.
stdphp
provides a set of basic classes and utility functions. It's mostly modeled after python, with some additions from javascript and ruby.
Show Me What You Got
Some examples of what stdphp
looks like.
Sort words in a string
print str('foo bar baz')->split()->map('strtoupper')->sort()->join(','); /// BAR,BAZ,FOO
Unicode fun
$str = str('Gänsefüßchen');
print count($str); /// 12
print $str['5:8']; /// 'füß'
print $str->upper(); /// 'GÄNSEFÜßCHEN'
Remove duplicates from a list
$dupes = [4,1,3,2,4,1,4,2,3,3,1,2];
print set($dupes); /// [4,1,3,2]
Sum every second number
$numbers = a(0,11,22,33,44,55,66,77,88,99);
print $numbers['::2']->reduce(operator('+')); /// 220
FizzBuzz
$x = lst(xrange(31));
$x['::3'] = repeat('Fizz');
$x['::5'] = repeat('Buzz');
$x['::15'] = repeat('FizzBuzz');
print $x['1:']; /// [1,2,"Fizz",4,"Buzz","Fizz",7,8,"Fizz","Buzz",11,"Fizz",13,14,"FizzBuzz",16,17,"Fizz",19,"Buzz","Fizz",22,23,"Fizz","Buzz",26,"Fizz",28,29,"FizzBuzz"]
Chunkify a list
If you know python, this is zip(*[iter(xs)]*n)
:
$a = [1,2,3,11,22,33,101,102,103];
print lst(zipargs(repeat(iter($a), 3))); /// [[1,2,3],[11,22,33],[101,102,103]]
Usage
The whole library is one single php file, std.php
:
include 'std.php';
$someList = lst("abc");
There's also a "local" version stdl.php
, which keeps stdphp
functions namespaced:
include 'stdl.php';
$someList = std\lst("abc");
stdphp
requires php 5.4+
Features
Factory functions
Objects, like strings or lists, are created with factories:
$someList = lst([1,2,3]);
$someString = str("abc");
This has two advantages: conciseness and ability to override default classes with inherited ones:
class MyList extends std\Lst
{
function myNewMethod() { return $this->join(' me '); }
}
std\_setclass('Lst', 'MyList');
// now, all library functions that return a list, will return MyList:
print str('foo bar')->split()->myNewMethod(); /// foo me bar
Iterables and iterators
stdphp
follows the pythonic concept of "iterables". Functions that iterate through their arguments don't enforce a particular type. Therefore you can pass any "iterable", including stdphp
objects, native php arrays and strings, and generic Traversable
objects:
$a = a(0,1,2,3);
$b = "abcd";
$c = array(9,8,7,6);
print lst(zip($a, $b, $c)); /// [[0,"a",9],[1,"b",8],[2,"c",7],[3,"d",6]]
There are several built-in iterator constructors for different purposes:
filter
map
repeat
xrange
zip
The following creates a "lazy" list of palindromic numbers. Since filter
, map
and xrange
are iterators, this list uses constant memory:
$xs = filter(
function($s) { return $s == $s['::-1']; },
map('str',
xrange(300000)));
Another example is an "endless" repeat
iterator that plays nicely with zip
:
print lst(zip('abcd', repeat('-'))); /// [["a","-"],["b","-"],["c","-"],["d","-"]]
Mapping and higher-order functions
The higher-order function getter
returns a closure that picks an item from a string or associative array.
// fetch the 2nd char from each string:
print a('ab','cd','ef')->map(getter(1)); /// ["b","d","f"]
getter
(alias by
) is especially useful with sort
, which, like in python, uses a functional key
argument to extract a comparison key.
$popularNames = [
['name' => 'Alfie' ,'rank' => 7],
['name' => 'Charlie' ,'rank' => 4],
['name' => 'Harry' ,'rank' => 1],
['name' => 'Jack' ,'rank' => 3],
['name' => 'Jacob' ,'rank' => 5],
['name' => 'Oliver' ,'rank' => 2],
['name' => 'Riley' ,'rank' => 8],
['name' => 'Thomas' ,'rank' => 6],
['name' => 'William' ,'rank' => 9]
];
// print top 3 names by rank
print lst($popularNames)->sort(by('rank'))->map(getter('name'))->get(':3'); /// ["Harry","Oliver","Jack"]
Similarly, attr
picks an attribute from an object argument:
class User {
function __construct($name) {
$this->name = $name;
}
}
$a = [new User("Harry"), new User("Oliver"), new User("Jack")];
print lst($a)->map(attr('name'))->join(','); /// Harry,Oliver,Jack
method
creates a closure that calls a specific method on the argument:
// call `String::reverse` on each element:
print s("Hello Foo Bar")->split()->map(method('reverse')); /// ["olleH","ooF","raB"]
stdphp classes
Here's a brief overview, for a complete list of methods refer to the API documentation.
List
Lists are created using constructors a()
or lst()
and provide the usual repertoire of methods:
print a('foo', 'bar', 'baz')->map('strtoupper')->join('-'); /// FOO-BAR-BAZ
Lists support python-alike slicing:
$a = a(0,1,2,3,4,5,6,7);
print $a[-3]; /// 5
print $a['1::3']; /// [1,4,7]
and slice assignments:
$a = a(0,1,2,3,4,5);
$a['2:4'] = 'abcd';
print $a; /// [0,1,"a","b","c","d",4,5]
String
Strings are unicode-aware (source encoding is assumed to be utf8, unless specified otherwise):
$a = s('fuß');
print count($a); /// 3
$b = s("fu\xDF", 'latin1');
$a == $b; /// true
Slicing works too, but not slice assignments: strings are immutable! Note: mb
extension is required for encoding and case conversions.
Dict
Dicts are associative arrays. There are several dict
constructors:
print d('a', 1, 'b', 2); /// {"a":1,"b":2}
print dict(['a' => 1, 'b' => 2]); /// {"a":1,"b":2}
print pairdict([['a',1], ['b',2]]); /// {"a":1,"b":2}
print keydict('abc', 42); /// {"a":42,"b":42,"c":42}
In addition to standard pythonic methods, dicts can be also mapped and filtered:
$a = dict(['a'=>'foo', 'b'=>'bar']);
print $a->map('strtoupper'); /// {"a":"FOO","b":"BAR"}
Set
Sets are just like python sets:
$a = set([1,2,3,4,5]);
print $a->intersection([5,3,9,1]); /// [1,3,5]
Re
re
creates a regular expression object. Unlike php, delimiters are not required, and flags can be passed as a second argument:
$r = re('[a-z]+', 'i');
print $r->sub('*', 'a1B2c3'); /// *1*2*3
find
and findall
return strings:
print re('[a-z]+')->findall('ab cd ef'); /// ["ab","cd","ef"]
match
and matchall
return "match objects":
print re('([a-z]+)(\d+)')->match('abc123')->group(2); /// 123
Build system
std.php
is generated from the src
directory using small c-alike preprocessor CPP
(in tools
dir). doxytest
runs tests which are embedded in the code and enclosed in @code...@endcode
or @test...@endtest
.
Todos
- wrappers for all php array/string functions
- iterable files and streams, as in
foreach (textfile('foo.txt', 'utf8')) as $line)...
itertools
methods likeproduct
orcombinations