12/08/2018, 14:58

Bundled PHP classes you might have not known about

in this post I will describe some native PHP features which are rarely used in common code implementations, but might significantly improve code quality if used in right situations. In short, this is a review of datasets, iterators, type handling, advanced dates handling and advanced using of ...

in this post I will describe some native PHP features which are rarely used in common code implementations, but might significantly improve code quality if used in right situations.

In short, this is a review of datasets, iterators, type handling, advanced dates handling and advanced using of closures and generators.

Standard PHP Library (SPL)

Most of developers use SPL autoloading features and some common classes like SplFileInfo, but this library also provides much more useful things which are being used quite rarely.

Datasets

One of the most common operations required during development is using datasets. And while most modern applications use databases to deal with ordering and sorting, sometimes processing large amounts of data with PHP might be very handy.

Doubly linked lists, queues and stacks

SplStack and SplQueue are two default extensions of SplDoublyLinkedList class, which allows to operate with subsequent data sets faster and more comfortable than using arrays.

As it comes from the names, SplStack implements LIFO (Last-In-First-Out) iteration and SplQueue implements FIFO (First-In-First-Out) iteration.

$list = new SplQueue(); // OR: new SplStack();

$list->push('a');
//OR: $list->enqueue('a'); // alias of `push` in queue
$list->push('b');
$list->push('c');

for ($list->rewind(); $list->valid(); $list->next()) {
    echo $list->current()."
";
}

Looks very simple and similar to something like Laravel Collections, but works much faster and available out of the box.

Heaps

If the order of data is dependent on it’s contents, a heap with sorting algorithm might help a lot. On the opposite to using array sorting or collection sorting, the heap will always have comparison algorithm defined inside of it.

With introducing the spaceship operator in PHP7 heaps became even more handy to work with.

class UserRankChart extends SplHeap
{
    protected function compare($user1, $user2)
    {
        // Move inactive users to bottom
        if (!$user1->active || !$user2->active) {
            return $user1->active <=> $user2->active
        }

        return $user1->likes <=> $user2->likes;
    }
}

$list = new UserRankChart;

$list->insert(new User([
    'id' => 1,
    'active' => false,
    'likes' => 0,
]);

$list->insert(new User([
    'id' => 2,
    'active' => true,
    'likes' => 5,
]);

$list->insert(new User([
    'id' => 3,
    'active' => true,
    'likes' => 2,
]);

for ($list->rewind(); $list->valid(); $list->next()) {
    echo $list->current()->id."
";
}

In this case order of users will be: 2, 3, 1

SplMaxHeap and SplMinHeap are two extensions of heap with the opposite sorting orderings: highest first or lowest first.

Priority queues

SplPriorityQueue is a combination of a queue and heap, which uses 2 arguments in push method: the element itself and its priority separately, while priority can be any value.

For example, we can implement such queue when processing mixed instances and their ranks separately

class SubscriptionsRankChart extends SplPriorityQueue
{
    protected function compare($rank1, $rank2)
    {
        // Move inactive users to bottom
        if (!$rank1->active || !$rank2->active) {
            return $rank1->active <=> $rank2->active
        }

        return $rank1->likes <=> $rank2->likes;
    }
}

$list = new SubscriptionsRankChart();

$list->insert($post, $post->rank);
$list->insert($user, $user->rank);
$list->insert($tag, $tag->rank);

//...

In this example the element pushed to the queue might be any instance, while its rank should be compatible with queue compare method.

Fixed-length arrays

This class operates exactly as any array-like object. But it has fixed length and allows only integers as index values.

In most cases, small arrays will always be faster and less memory-consuming than objects. But with huge amount of elements, SplFixedArray gives great advantages.

Iterators

The SPL library offers a huge amount of different iterable classes. Most of them are rarely used within frameworks. But they give a lot of advantages if used properly.

Let’s take a look at several most interesting of them:

  • CallbackFilterIterator — implements an iterator which filters elements before passing them to output. The behavior is mostly similar to array_filter or filter method of most collection pattern implementations like in Laravel. The difference is that filtering callback is passed to constructor: $i = new CallbackFilterIterator($anotherIterator, $filterCallback);
  • FilterInterator — similar to callback filter, but the filtering procedure must be defined in accept method, which is abstract by default.
  • InfiniteIterator — very interesting implementation of iterator, which automatically rewinds when it reaches the end. Might be very useful when needed to iterate through set of elements repeatedly (e. g. weekdays)
  • LimitIterator — accepts any another iterator and outputs a range defined by $offset and $count passed to constructor.
  • MultipleIterator — provides attachIterator and detachIterator methods to inject multiple different iterators inside and then use them as a single iterable element.

See full list at PHP: Iterators - Manual

Type handling

PHP does not have strict type handling by default. This gives both advantages and disadvantages. But any time you need to validate data type you can use native classes to work with it.

Abstract SplType class and its extensions: SplString, SplInt, SplFloat and SplBool provide a very handy way to deal with it.

<?php
$string = new SplString("Testing");
$int = new SplInt(94);

try {
    $string = array();
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL;
}

try {
    $int = 'Try to cast a string value for fun';
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL;
}

As you can see, an instance of this class detects reassignment and throws an exception if the value if the type does not match.

But the most interesting is the SplEnum class.

How many times did you have some code like this:

class Post extends Model
{
    //...

    const MODERATION_STATUS_BLOCKED = 'blocked';
    const MODERATION_STATUS_DISCARDED = 'discarded';
    const MODERATION_STATUS_PENDING = 'pending';
    const MODERATION_STATUS_APPROVED = 'approved';

    const STATUS_DRAFT = 'draft';
    const STATUS_PUBLIC = 'public';
    const STATUS_DRAFT_PUBLIC = 'draft_public';

    //...

    protected $filleble = [
        //...
        'status',
        'moderation',
        //...
    ];
}

Well, we have plenty of that in Viblo sources             </div>
            
            <div class=

0