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.