Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Standard PHP Library (SPL)

Overview

The Standard PHP Library (SPL) is a collection of Classes and Interfaces created to solve common programming problems. Particularly, those of traversing aggregate and recursive data structures such as XML trees, arrays, lists, database result sets, directories, etc. All of this is done via the use of Iterators. This library is analogous to the prominent java.util.* Java API.

In my experience, most PHP developers have failed to realize the power and structure that SPL can bring to your code.  It's structured using the Decorator (also known as Wrapper) pattern throughout the library and when used properly, it can make your code very readable, structured, and extensible. 

This library has been built into PHP since 5.0.0. It does not require any separate installation or special configuration. So, let's jump right in:

Before we dig into any library class, let's briefly talk about the interfaces that support all of this and and form the core of the entire library:
  • Countable: classes implementing this interface can be passed into the count  function.
  • Traversable: marker interface to detect if a class can be used in a foreach( ) construct.
  • Iterator: classes implementing this can be iterated themselves internally. If you wanted to extend SPL with your own custom iterator, you could implement this interface.
  • ArrayAccess: provides access to object state as an array
  • Serializable: used to serialize and unserialize objects. Classes implementing this interface will no longer support the __wakeup( ) and __sleep( ) functions. The serialize( )  and unserialize( ) functions will be used instead.

Iterators

SPL provides standard iterators to be used with Arrays and Objects built on the interfaces I mentioned above. Typically, these work when called within the context of a foreach( ) statement. Let's start with a simple ArrayIterator example:


class SkipMapIterator extends ArrayIterator {

private $func; // map function func(x)
private $skip; // skip factor

public function __construct($iter, $skip, $func) {
parent::__construct($iter); 
$this>skip = $skip;
$this->func = $func;
}

public function current() {
$x = parent::current(); 
$pos = parent::key();
if($pos % $this>skip == 0) {
return call_user_func($this->func, $x);
}
return $x;
}
}


$numbers = array(1,2,3,4,5,6,7,8,9);

$squareIter = new SkipMapIterator($numbers, 2, 
function($x) {
return pow($x,2);
});

echo '[';
foreach($squareIter as $key=>$num) {
echo $num;
if($key < $squareIter->count() - 1){
echo ',';
}
}
echo ']';

In the example above, I subclassed the ArrayIterator class in order to create a SkipMapIterator that can take a function and apply it to each element in the list skipping "$skip" elements. In the example above, as the list is iterated, the function is applied to every other element.

The output is the following:

[1, 2, 9, 4, 25, 6, 49, 8, 81]

It skips over every other element. This operation is very similar to an array_walk( ) function but gives you a lot more control. A very trivial example indeed, but proofs the concept. Imagine having a list of file names that must be updated together. Loop over the file names array, and the function performs the same update to all files.

Let's take a look at another example:

class RecurringEventPlanner  { 

private $duration; // The duration of the recurring event
private $day; // Day to plan event
private $name; // Name of the event

private static $DAYS = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');

public function __construct() {
$this->name = 'Unknown Event';
$this->day = 'Sunday'; // Default to day 'Sunday'
$this->duration = 7; // 1 week
}

public function withName($name) {
$this->name = $name;
return this;
}

public function withDuration($duration) {
$this->duration = $duration;
return this;
}

public function onDay($day) {
$this->day = $day;
return this;
}


public function printEvent() {

$weekly = new InfiniteIterator(new ArrayIterator(self::$DAYS));
$event = new LimitIterator($weekly, 0, $this->duration);
foreach ($event as $day) {
print 'On '. $day. ': ';
if($day == $this->day) {
print '******'. $this->name. '******';
}
else {
print 'Nothing happens';
}
print "\n";
}
}
}

$sundayMass = new RecurringEventPlanner();
$sundayMass->withName('Sunday Mass at 9:00 am');
$sundayMass->withDuration(14); // 2 weeks
$sundayMass->printEvent();

As I mentioned at the beginning of this post, one of the core principles behind the SPL APIs is the use of the Decorator (Wrapper) pattern. If you take a look at the printEvent( ) function above, I attempted to wrap Iterators within other Iterators and enhance its functionality with every nested class. I began with a simple ArrayIterator to loop over the days of the week. I wrapped this iterator with an InfiniteIterator that will allow me to endlessly iterate over and over the days in the week. Of course, I can't just iterate for ever, so I wrapped that iterator further using a LimitIterator so that the user can provide an end date for the event. The RecurringEventPlanner class will print a weekly schedule with the event for a period of a given amount of days (in our example 2 weeks).

Data Structures

Iterators are just one part of the SPL library, let's take a look at some of the data structures that the SPL library provides. On a daily basis, you would probably use things like: stack, queue, and heap, so let's focus on them.

Implemented with a DoublyLinkedList, the stack is a data structure with Last-In, First-Out (LIFO) functionality with typical push( ) and pop( ) functions. Notice that as you push items onto the stack, the stack's internal pointer is always pointing at the next item. To print all of the contents of the stack, you must rewind this pointer.

$stack = new SplStack();
$stack->push('First In, Last Out');
$stack->push('Second In');
$stack->push('Last In, First Out');

$stack->rewind();

while($stack->valid())
{
echo $stack->current(), PHP_EOL;
$stack->next();
}

The stack is a very useful programming structure. Alongside the SplStack is the SplQueue with First-In, First-Out (FIFO) functionality (basically same code). Much more interesting and powerful are the SplHeap structures. Heaps are basically tree structures that satisfy the ordering principles of the heap nodes. You have the SplMaxHeap (maximum key at the top) and SplMinHeap (minimum key at the top) flavors as well. I won't spend time talking about the internals of the data structures themselves, there is extensive material on the subject out there and a lot of math involved; suffice to say, they are ready for use with this library so that you don't have to implement them yourself.

Let's pick a more complex data structure from the list, SplPriorityQueue. A priority Queue is implemented internally using a max heap and exposes a compare(priori1, priori2) function that will be used to sort the keys within the tree structure (heap). By default, if no comparison function is provided, it will use the key's natural ordering of elements, i.e strings will be compared in lexicographical order, numbers in numerical order, etc. When storing objects, it is necessary to provide your own comparison function. Let's look at an example, suppose you are trying to implement a print queue that routes jobs to certain printers in priority:


class PriorityPrintQueue extends SplPriorityQueue 
{
private $prioriTable;

public function __construct() {
$this->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
$this->prioriTable = array(
'/10\..*/' => '1',
'/20\..*/' => '2',
'/30\..*/' => '3',
'/40\..*/' => '4'
);
}

public function compare($priority1, $priority2)
{
if ($priority1 === $priority2) {
return 0;
}
return $priority1 < $priority2 ? -1 : 1;
}

public function add($printer, $host) {

$priority = 0;

// search for the correct priority depending on host
foreach($this->prioriTable as $h => $p) {
if(preg_match($h, $host) > 0) {
$priority = $p;
break;
}
}
$this->insert($printer, $priority);
}


public function sendJob($jobName) {
$this->top();
$printer = $this->extract();
echo 'Sending job to printer: '. $printer['data']. "\n";

// route job...
}
}

$printQ = new PriorityPrintQueue();

$printQ->add('Apple Laser Printer', '40.344.23.233');
$printQ->add('HP Scanner Photosmart', '10.20.30.40');
$printQ->add('Logitech All in One' , '30.50.62.77');
$printQ->add('Caselogic Printer', '20.234.900.765');

$printQ->sendJob('Job 1');
$printQ->sendJob('Job 2');
$printQ->sendJob('Job 3');
$printQ->sendJob('Job 4');

Running this code will print the following:

Sending job to printer: Apple Laser Printer
Sending job to printer: Logitech All in One
Sending job to printer: Caselogic Printer
Sending job to printer: HP Scanner Photosmart

As you can expect, the first job will be routed to the Apple Laser Printer because its host IP is ranked with highest priority in the PriorityPrintQueue class. In our compare( ) function, we have defined the highest number to mean higher priority. We can certainly change this if we wanted to.

Autoloading

Autoloading is an internal PHP mechanism. When a class is instantiated, the __autoload( ) method is called. This is really useful when writing object oriented code where you would typically have one class per PHP file.

You can override this method and provide your own autoloading function. PHP will look at your script first and invoke the autoload function if you have provided one. This is heavily discouraged and considered bad practice, to the point where it might be deprecated in future releases. However, if properly done, autoloading is really useful as it can eliminate the clutter of using many  require* and include* statements at the beginning of your script.

In PHP 5, SPL provides a more flexible autoloading mechanism, which you can use to take advantage of the power of this mechanism while not breaking your entire application. This practice is followed heavily by systems such as Composer. Composer is a PHP Dependency Management tool that, if configured to do so, will automatically provide the scaffolding necessary to autoload your classes into your application without you having to explicitly require/include all of the files.

 // init.php

spl_autoload_register(null, false);

spl_autoload_extensions('.php, .class.php, .lib.php');

// Custom class loader that will search the classes folder for any
// to instantiate classes
spl_autoload_register(function($class)
{
$filename = $class . '.class.php';
$file ='src/' . $filename;
if (!file_exists($file)) {
return false;
}
require_once $file;
});


-------------------------------------------------------------------------------
// main.php

require_once('init.php');
// instantiate MyClass w/o having to include the class in the script
$hello = new MyClass();

// say hello!
$hello->sayHello();


In the example code above, I registered a custom class loader function via the SPL autoloading mechanism. This function will be called internally every time a class is instantiated without having to explicitly include every single class file that I need. The ini.php script can manage the location of all your classes in a central location. Once this is done once, application developers just need to worry about using them.

The power of autoloading is not just in cutting down in the need to include files. You can also use it enforce coding standards and best practices. For instance, I can use the spl_autoload_extensions function to indicate that all class files must end in ".class.php". Also, I can force class name conventions in a style similar to PSR-0. For more information on PHP coding standards, you can read more here.

Conclusion


With the advent of the SPL libraries in PHP 5, you can make your code a lot more readable, structured, and extensible. All in all, more Object Oriented, which obviously is a nice paradigm to follow. In this post we started by taking a look at iterator classes and interfaces and how you can extend them to create very powerful Iterator classes for your application. The need to iterate is a given in any application. Also, we discussed some advanced data structures that you can use in your applications such as Stacks, Queues, and Heaps, which you would otherwise need to write yourself. And finally, we briefly explained the PHP native concept of autoloading and how it can improve the readability and maintainability of your application.

Hope this blog helps you in your endeavor to write more Object Oriented PHP code!

Stay tuned!

Resources

  1. http://www.php.net/manual/en/book.spl.php
  2. http://php.net/manual/en/language.oop5.autoload.php
  3. http://www.phpro.org/tutorials/SPL-Autoload.html
  4. https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
XTDMHZQW4S85


This post first appeared on LUISATENCIO.NET, please read the originial post: here

Share the post

Standard PHP Library (SPL)

×

Subscribe to Luisatencio.net

Get updates delivered right to your inbox!

Thank you for your subscription

×