GNU/Linux Inside

PHP Extension Writing: Namespaces

I’m fairly new to PHP extension writing. I’ve just gotten into it in order to optimize some existing PHP 5.3 code for my WebKernel project. However, there was one fundamental problem that I could not find the solution to anywhere online – how do you define a function within a namespace!? WebKernel used namespaces extensively, so I needed to know the solution to the problem.

Namespaces are new as of PHP 5.3. Therefore, there’s very few people actually writing extensions with namespace support. To make matters worse, documentation of the Zend core is very poor. Much of my time is spent reading through the code, trying to figure out what macros do what, etc. This was another one of those cases.

Normal PHP Functions:

Normal PHP functions are placed within the functions list using the PHP_FE macro. The actual function is defined using PHP_FUNCTION. So your code may look like this:

1
2
3
4
5
6
7
8
9
10
static function_entry my_functions[] = {
// ...
PHP_FE( myfunc, NULL )
// ...
};
 
PHP_FUNCTION( myfunc )
{
// Function body here
}

If you were to call myfunc() from within userland (within a PHP script), it would execute the C code defined within the body of PHP_FUNCTION( myfunc ). Simple enough. Now what if we wanted namespaces?

Using Namespaces

The short answer:
Replace PHP_FE( myfunc, NULL ) with ZEND_NS_FE( "myns", myfunc, NULL ). But if you actually want to know why, keep reading.

The detailed answer:
PHP_FE is defined within main/php.h. That points us to the ZEND_FE macro defined within Zend/zend_API.h. While looking through this file, I noticed a ZEND_NS_FE macro in there, and figured it must be referring to namespaces. So I figured that logically, there would be a PHP_NS_FE macro, right? Nope. There’s no such macro defined anywhere. At least not at this point in time. Hopefully there will be for the final release of 5.3.
yourself, however that will ruin your chances of your extension becoming portable. Other developers aren’t going to want to patch their php.h file to use it.

1
2
#define ZEND_FE(name, arg_info)						ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
#define ZEND_NS_FE(ns, name, arg_info)					ZEND_NS_FENTRY(ns, name, ZEND_FN(name), arg_info, 0)

Looking over the macros, you see that both macros make use of the ZEND_FN macro. A quick glance at that macro shows that it converts our “myfunc” function into “zif_myfunc”:

1
#define ZEND_FN(name) zif_##name

This means that internally, zend will use the same function name regardless of whether or not it is contained within a namespace. In other words, we don’t even have to touch our PHP_FUNCTION line! Great – so then what’s different? Let’s take a look at ZEND_NS_FENTRY:

1
#define ZEND_NS_FENTRY(ns, zend_name, name, arg_info, flags)		ZEND_RAW_FENTRY(ZEND_NS_NAME(ns, #zend_name), name, arg_info, flags)

The difference here is that Zend is making use of the ZEND_NS_NAME macro:

1
#define ZEND_NS_NAME(ns, name)			ns"\\"name

Ah-ha! (Ignoring the fact that it’s, at present, at the top of the file.) While internally our function name is no different, Zend will only call it if it is prefixed with the namespace name from within userland. The above macro converts our function name to “myns\myfunc”. So, our updated code may look like this:

1
2
3
4
5
6
7
8
9
10
11
12
#define MY_NS "myns"</code>
 
static function_entry my_functions[] = {
// ...
ZEND_NS_FE( MY_NS, myfunc, NULL )
// ...
};
 
PHP_FUNCTION( myfunc )
{
// Function body here
}

We can then call our function via “myns\myfunc”. Remember – you must use ZEND_NS_FE. As of this time of writing, PHP_NS_FE does not exist! Of course, that could easily be solved by adding it to your own source files yourself, but it’s still a messy task. I’ve submitted a bug report to the PHP team detailing the additions (I couldn’t find where to submit a patch), so hopefully it’ll make it in. Until then, feel free to add this to your header file, along with any other ZEND_NS_* aliases you may need:

1
2
3
#ifndef PHP_NS_FE
#    define PHP_NS_FE ZEND_NS_FE
#endif

Summary

While diving into the C code isn’t necessary to use namespaces, it does greatly improve your understanding of how the system works. Because there is so little documentation, I encourage you to keep looking through PHP’s source and see what you find. There are goodies hidden everywhere that may be incredibly useful to you, and save you a lot of time. Look through existing extensions within the ext folder and see if any of them use methods that you are interested in.

It was the unfortunate circumstance that none of the extensions did make use of namespace support. So I was on my own to look for it. I hope this helps save some frustration for others, especially those new to Zend that are just trying to figure out whether or not porting their code to C is worth the effort.

No Trackbacks

You can leave a trackback using this URL: http://mikegerwitz.com/php-extension-writing-namespaces/trackback/

One Comment

  1. Is there a callback mechanism for the using of namespaces? e.g. if i want to use a namespace from php then i get a callback in my extension an i can load e.g. an shared library and provide more functions.. ?

    Posted November 2, 2010 at 2:33 pm | Permalink

Post a Comment

Your email is never shared. Required fields are marked *

*
*