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

Typed PHP, Stronger Types for Cleaner Code (2014)

Extensions

Zephir

Zephir is a framework for writing compilable and installable PHP extensions, using a PHP superset language sharing some similarity with C code. Zephir isn’t strictly a PHP extension, nor are Zephir libraries written in true PHP.

It’s part of the same collective from which the Phalcon framework comes, and Phalcon is itself a PHP extension. This should get interesting!

Installing Zephir

Zephir requires a few libraries, in order to compile correctly. We can install these with:

1 $ sudo apt-get install git gcc make re2c php5 php5-json php5-dev libpcre3-dev

Next, we need to install the JSON-C library (which Zephir uses to compile extensions):

1 $ git clone https://github.com/json-c/json-c.git && cd json-c && sh autogen.sh\

2 && ./configure && make && sudo make install

These commands will clone the JSON-C repository, configure and compile it. Finally, we need to install Zephir:

1 $ git clone https://github.com/phalcon/zephir && cd zephir && ./install -c

That should have installed a usable version of Zephir. You can check that it’s working by heading into the clone folder and running:

1 $ zephir version

Using Zephir

Using Zephir is relatively simple (considering the work that actually goes on). Let’s begin by initialising a new extension skeleton project:

1 $ zephir init type

This will create a skeleton project folder in the current working directory. Navigate into the new type directory and run:

1 $ ls -la

2

3 ext/ type/ config.json

Extension classes go in the type folder (it’s specific to the name of the extension, which we gave the init command). Make a find in there, called StringType.zep, and open that file in your editor.

The Zephir syntax is quite similar to PHP, but with a twist of C style. You can find a reasonable amount of documentation at http://www.zephir-lang.com/index.html.

Create the following class:

1 namespace Type;

2

3 class StringType

4 {

5 protected data;

6

7 public function __construct(var data)

8 {

9 let this->data = data;

10 }

11

12 public function length()

13 {

14 return strlen(this->data);

15 }

16 }

Other than the missing $ symbols, and the var/let keywords added, this is pretty understandable. Save the file and (from the base extension folder) run:

1 $ zephir build

2

3 Compiling...

4 /bin/bash /vagrant/zephir/type/ext/libtool --mode=compile gcc -I. -I/vagrant/\

5 zephir/type/ext -DPHP_ATOM_INC -I/vagrant/zephir/type/ext/include -I/vagrant/z\

6 ephir/type/ext/main -I/vagrant/zephir/type/ext -I/usr/include/php5 -I/usr/incl\

7 ude/php5/main -I/usr/include/php5/TSRM -I/usr/include/php5/Zend -I/usr/include\

8 /php5/ext -I/usr/include/php5/ext/date/lib -DHAVE_CONFIG_H -O2 -fvisibility=\

9 hidden -Wparentheses -flto -c /vagrant/zephir/type/ext/type/stringtype.zep.c\

10 -o type/stringtype.lo...

Zephir cross-compiles the extension class files to Plain Ol’ C, and adds the class loading code. The end of the build output should look something like:

1 Installing...

2 Extension installed!

3 Add extension=type.so to your php.ini

4 Don't forget to restart your web server

…So we need to add the extension to the php.ini file:

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

This will have installed the Type extension we just created. We can check that it’s installed by running:

1 $ php -i | grep "type => enabled"

2

3 type => enabled

If you see that line returned, you know the extension is installed, and ready to go.

Using this new extension is as simple as:

1 <?php

2

3 $string = new Type\StringType("Hello World");

4

5 print $string->length();

The namespace and class reside completely within the compiled extension file. Zephir extensions can use pre-existing core and extension namespaces/classes. The can be used by Plain Ol’ PHP code (provided the extension is registered by the time it’s used).

Zephir extensions can even override core functions, with better-performing versions.

Conclusion

Extensions make our lives significantly easier, by handling things like boxing and unboxing for us. They let us create better-performing code (as in the case of Zephir) and stricter types (as in the case of SPL Types).

We don’t have to use these to make a cleaner system. If we do, we can expect to have a much strong type system, without the hard work that library-only code expects of us.