SPL Types - Extensions - Typed PHP, Stronger Types for Cleaner Code

Typed PHP, Stronger Types for Cleaner Code (2014)

Extensions

SPL Types

SPL (or Standard PHP Library) is a library of additional types to augment those native to core PHP. There are some popular classes (like LogicException and ArrayObject). Some of the SPL ships with standard PHP installations. The parts we’re going to look at shortly do not…

You can find these mystery libraries at http://www.php.net/manual/en/book.spl-types.php

This section assumes you’re using the Vagrant box explained earlier. If not, please set that up first. These commands are Linux-specific and depend on the pre-installed modules explained earlier.

Installing SPL Types

To install them, run the following commands:

1 $ sudo apt-get install libpcre3-dev php5-dev

2

3 Reading package lists... Done

4 Building dependency tree

5 Reading state information... Done

6 The following extra packages will be installed:

7 autoconf automake autotools-dev build-essential...

1 $ sudo pecl install SPL_Types

2

3 downloading SPL_Types-0.4.0.tgz ...

4 Starting to download SPL_Types-0.4.0.tgz (8,388 bytes)

5 .....done: 8,388 bytes

6 6 source files, building

7 running: phpize...

These two commands install the pre-requisites for compiling PECL extensions. PECL is a repository just like PEAR. If you’ve heard of neither, then don’t worry. All you need to know is that the SPL Types are hosted here, so to install them we need to be able to compile PECL extensions.

1 $ sudo bash -c "echo extension=spl_types.so >> /etc/php5/cli/php.ini"

This command appends extension=spl_types.so to the php.ini file (as per the installation instructions).

1 $ sudo service php5-fpm restart

2

3 php5-fpm stop/waiting

4 php5-fpm start/running, process...

This command restarts PHP-FPM - the process that interprets PHP command line instructions and Nginx web requests. These commands should have installed the SPL Types, but just to be sure, run the following command:

1 $ php -i | grep SPL_Types

2 SPL_Types

If you see that SPL_Types line, then you should be good to go!

Using SPL Types

Let’s look at a few examples of how these classes can be used:

1 <?php

2

3 class NumberType extends SplFloat

4 {

5 /**

6 * @return float

7 */

8 public function toInteger()

9 {

10 return round($this);

11 }

12

13 /**

14 * @return string

15 */

16 public function toString()

17 {

18 return (string) $this;

19 }

20 }

21

22 $number = new NumberType(13.86);

23

24 print $number->toInteger(); // 14

25 print $number->toString(); // "13.86"

26

27 print (float) $number + 1.00; // 14.86

28 print $number * 12; // 156

The toInteger and toString methods do similar things to the box classes. The magic happens when we do basic arithmetic with the $number object. SPL Types are automatically unboxed when they are used in arithmetic expressions, or cast or concatenated. Any operator that would normally with with a scalar type will work with the corresponding SPL Type.

Here’s another example:

1 <?php

2

3 class StringType extends SplString

4 {

5 /**

6 * @param int $start

7 * @param mixed $length

8 *

9 * @return StringType

10 */

11 public function slice($start = 0, $length = null)

12 {

13 if ($length === null) {

14 return new static(substr($this, $start));

15 }

16

17 return new static(substr($this, $start, $length));

18 }

19 }

20

21 $string = new StringType("Hello World");

22

23 print $string->slice(6); // "World"

We can design our types so that they return new instances. This gives us a simple chaining interface.

Be careful when assuming the return type of native PHP functions. Be sure to check them before the call to new static() or you may encounter fatal errors.

Scalar Objects

Nikita Popov is a prolific contributor to PHP (both core and user-land). He’s made libraries such as PHP-Parser which is used all over the web, and in popular frameworks (like Laravel). He’s championed many multiple RFCs, which have become parts of core PHP.

He’s also created a custom extension which allows the registration of custom type handlers. You can find it at https://github.com/nikic/scalar_objects.

We’re going to install and use this module to get even closer to our ideal type handling situation…

This section assumes you’re using the Vagrant box explained earlier. If not, please set that up first. These commands are Linux-specific and depend on the pre-installed modules explained earlier.

Installing Scalar Objects

First up, we need to install the Git command-line tool:

1 $ sudo apt-get install git

2

3 Reading package lists... Done

4 Building dependency tree

5 Reading state information... Done

6 The following extra packages will be installed:

7 git-man liberror-perl...

Following this, we can clone and build the extension:

1 $ git clone https://github.com/nikic/scalar_objects.git

2

3 Cloning into 'scalar_objects'...

4 remote: Reusing existing pack: 213, done.

5 remote: Total 213 (delta 0), reused 0 (delta 0)

6 Receiving objects: 100% (213/213), 75.36 KiB, done.

7 Resolving deltas: 100% (112/112), done.

1 $ cd scalar_objects && phpize && ./configure && make && sudo make install

These commands will the Scalar Objects extension, but we still need to add it to the configuration: $ sudo bash -c "echo extension=scalar_objects.so >> /etc/php5/cli/php.ini"

This command resembles the one we used to install the SPL Types. We’re essentially doing the same thing, so we need to restart PHP5-FPM:

1 $ sudo service php5-fpm restart

2

3 php5-fpm stop/waiting

4 php5-fpm start/running, process...

This should complete the process of installing the Scalar Objects extension, but we can make sure it’s working by running the following command:

1 $ php -i | grep scalar

2

3 scalar_objects

4 scalar-objects support => enabled

Using Scalar Objects

The new extension adds a method we can use to register these type handlers. This is how you we can use it:

1 <?php

2

3 class StringHandler

4 {

5 /**

6 * @param int $start

7 * @param mixed $length

8 *

9 * @return StringType

10 */

11 public function slice($start = 0, $length = null)

12 {

13 if ($length === null) {

14 return substr($this, $start);

15 }

16

17 return substr($this, $start, $length);

18 }

19 }

20

21 register_primitive_type_handler("string", "StringHandler");

22

23 $string = "Hello World";

24

25 print $string->slice(6); // "World"

This is easier than boxing scalar types, as we don’t have to pull native types out of class instances. This is easier than SPL Types, as we don’t have to put native types into class instances.

There are seven supported types:

· null

· bool

· int

· float

· string

· array

· resource

You may be wondering whether this extension plays nicely with SPL Types. The answer is probably not. You shouldn’t mix these extensions and since the Scalar Objects extension does everything SPL Types you shouldn’t need both.