Hacking PHP5

Christian Weiske


Table of Contents

Preface
1. Defining classes
Adding parameter reflection
Parameter information with ARG_INFO
Reflecting classes and functions in your php script

Preface

This is no full book; I just wrote the reflection chapter because there was no documentation about it and I had a hard time figuring it out. Perhaps I'll write more, but don't rely on that.

This document is licensed under a Creative Commons license.

Chapter 1. Defining classes

Adding parameter reflection

Unlike PHP4, PHP5 doesn't just let you read all defined classes and class methods, but even such things like method parameters, parameter types, static class variables, ...

By default, PHP knows many things about your extension and the default functions, but the most cool thing is missing: The class parameters and parameter types. You as an extension author have to write some additional code to provide the necessary information for PHP to get it. This small howto shows you what you need.

First, let's have a look at the SPL source code in ext/spl/spl_directory.c:

SPL_METHOD(DirectoryIterator, openFile)
{
    ...
}

...

static
ZEND_BEGIN_ARG_INFO_EX(arginfo_dir_openFile, 0, 0, 0)
    ZEND_ARG_INFO(0, open_mode)
    ZEND_ARG_INFO(0, use_include_path)
    ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO();

...

static zend_function_entry spl_ce_dir_class_functions[] = {
    SPL_ME(DirectoryIterator, __construct,   arginfo_dir___construct, ZEND_ACC_PUBLIC)
    SPL_ME(DirectoryIterator, rewind,        NULL, ZEND_ACC_PUBLIC)
    SPL_ME(DirectoryIterator, valid,         NULL, ZEND_ACC_PUBLIC)
...
    SPL_ME(DirectoryIterator, isDot,         NULL, ZEND_ACC_PUBLIC)
    SPL_ME(DirectoryIterator, openFile,      arginfo_dir_openFile, ZEND_ACC_PUBLIC)
    SPL_MA(DirectoryIterator, __toString, DirectoryIterator, getFilename, NULL, ZEND_ACC_PUBLIC)
    {NULL, NULL, NULL}
};

At first, the method openFile of class DirectoryIterator is defined. Is it registered as official function with zend_function_entry, so that PHP knows that it can be used.

Now if you look at the

SPL_ME(...)

entries in the function registration table, you will see a NULL as third parameter in many lines. This means that there is no extra parameter information. However, for openFile, it is arginfo_dir_openFile. It tells PHP to look at the argument information structure with name arginfo_dir_openFile.

Parameter information with ARG_INFO

An argument information structure looks like this:

static ZEND_BEGIN_ARG_INFO(<funcname>, 0)
    ZEND_ARG_INFO(0, parametername1);
    ... (more parameter definitions)
ZEND_END_ARG_INFO();

There are two different ARG_INFO structures:

ZEND_BEGIN_ARG_INFO_EX(<funcname>, 0, 0, <number of required parameters>)

and

ZEND_BEGIN_ARG_INFO(<funcname>, 0)

The first one allows you to define the number of required parameters as the fourth parameter. If you don't need this (all are required), you should use the second one for simplicity's sake.

Note

It's good practice to use the following scheme for argument information function names: arginfo_<classname>_<methodname>

The parameter definition itself can be done with two different functions, too:

ZEND_ARG_OBJ_INFO(0, <parametername>, <parameterclass>, <allow_null>)
ZEND_ARG_INFO(0, <parametername>)

With the first one you define the name of the parameter (e.g. file_handle or resource) and as third parameter the class of which the parameter has to be. Pass 1 as fourth parameter if you want to allow NULL values, 0 otherwise. Note that PHP uses this information for extra validation, so PHP will print out and error if you pass a parameter of a different type in your php scripts or a null when it's not explicitely allowed.

If you have a mixed type or don't want to specify it, use the second, simple one.

Note

If you want to have a look at the reflection implementation in the zend engine, you could begin at Zend/zend_API.h, line 60 and Zend/zend_reflection_api.c.

Reflecting classes and functions in your php script

Note

There is a PHP5+PHP-Gtk2 reflection browser at cweiske.de which does the whole thing.

First, use get_declared_classes() to get all classes known to your php installation.

Then make a ReflectionClass object for the class you want to inspect:

$refl = new ReflectionClass('ReflectionClass');

Now you can use the function getMethods() to retreive all the functions ReflectionClass provides:

$methods = $refl->getMethods();

You have an array of ReflectionMethod objects now which you can inspect further. getParameters() will give you all the defined parameters, and getNumberOfRequiredParameters() the non-optional ones.

Play around with reflection; there is almost nothing you can't reflect - even line numbers of (userland) class declarations can be read.