Symisc PH7 Engine
An Embeddable PHP5 Engine

Introduction To The Constant Expansion Mechansim.

The following quick guide is what you do to start experimenting with the PH7 constant expansion mechanism without having to do a lot of tedious reading.

A constant is an identifier (name) for a simple value. As the name suggests, that value cannot change during the execution of the script.


A valid constant name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. Constants name are case-sensitive.

The constant expansion mechanism under PH7 is extremely powerful yet simple and work as follows:


Each registered constant have a C procedure associated with it. This procedure is known as the constant expansion callback which is responsible of expanding the invoked constant to the desired value. For example the C procedure associated with the “__PI__” constant expands to 3.14 (the value of PI), the “__OS__” constant expands to the name of the host Operating Systems (Windows, Linux, etc.) and so on.


Constants and their associated callbacks are registered via a single interface: ph7_create_constant().


We will start our tutorial by creating a simple constant named the __PI__ constant. That is, when the __PI__ identifier is seen in the running script, it's associated procedure (see below for the implementation) gets called by the underlying PH7 virtual machine. This procedure is responsible of expanding the PI  identifier to it's value (3.14 in our case).


The PH7 engine require that the constant expansion callback signature must correspond to this:

void (*xExpand)(ph7_value *,void *)

That is, a procedure that takes two arguments. The first argument is a pointer to a ph7_value that the procedure must fill with the desired value for example 3.14 (value of PI) is stored in this pointer. Use the following interfaces to populate the ph7_value with the desired value:


ph7_value_int()

ph7_value_int64()

ph7_value_bool()

ph7_value_null()

ph7_value_double()

ph7_value_string()

ph7_value_string_format()

ph7_value_resource()


The second and last argument is a copy of the fourth argument to the ph7_create_constant() function which is forwarded verbatim by engine.

Continuing with our __PI__ constant, here is the C procedure associated with it:


void PI_Constant(

     ph7_value *pValue, /* Store expanded value here */

      void *pUserData /* User private data (unused in our case) */

  ){

    /* Expand the value of PI */

     ph7_value_double(pValue,3.1415926535898);

}


As you can see, the PI_Constant() is a simple C procedure that expand the value of PI using the ph7_value_double() interface.

Another, more complex constant is the __TIME__ constant which expands to the current local time, here is the C procedure associated with it:


#include <time.h>

void TIME_Constant(ph7_value *pValue,void *pUserData)

{

   struct tm *pLocal;

   time_t tt;

   /* Get the current local time */

   time(&tt);

   pLocal = localtime(&tt);

   /* Expand the current time now */

   ph7_value_string_format(pValue,

"%02d:%02d:%02d",

                   pLocal->tm_hour,

                   pLocal->tm_min,

                   pLocal->tm_sec

              );

}


We get the current local time using the libc localtime() routine, then we expand a printf() like formatted string holding the current time using the ph7_value_string_format() interface.

A final example with the __OS__ constant which expands to the name of the host Operating System.


void OS_Constant(ph7_value *pValue,void *pUserData)

{

  #ifdef __WINNT__

     ph7_value_string(pValue,"Windows",-1 /*Compute input length automatically */);

  #else

    /* Assume UNIX */

    ph7_value_string(pValue,"UNIX",-1 /*Compute input length automatically */);

  #endif /* __WINNT__ */

}

We use ph7_value_string() to expand the name of the host OS. Of course a more serious implementation would call uname() rather than using #ifdef macros. This is what the real built-in PHP_OS constant does.

Test The Constant Expansion Mechanism

Now, we have implemented our constants expansion procedures, it's time to test the expansion mechanism. For that we will create a simple PHP program that invokes each of the created constants (__PI__, __TIME__ and __OS__) and displays their expanded values. Here is, the PHP program:


<?php
     echo
'__PI__ value: '.__PI__.PHP_EOL;

     echo
'__TIME__ value: '.__TIME__.PHP_EOL;

     echo
'__OS__ value: '.__OS__.PHP_EOL;

?>

When running, you should see something like that:

__PI__ value: 3.1415926535898

__TIME__ value: 15:02:27

__OS__ value: UNIX


Now, the main program. Note that you can get a working version of this program here


  1. int main(void)

  2. {

  3.    ph7 *pEngine; /* PH7 engine */

  4.    ph7_vm *pVm; /* Compiled PHP program */

  5.    int rc;

  6.    /* Allocate a new PH7 engine instance */

  7.    rc = ph7_init(&pEngine);

  8.    if( rc != PH7_OK ){

  9.    /*

  10.     * If the supplied memory subsystem is so sick that

  11.    * we are unable to allocate a tiny chunk of memory

  12.    * there is no much we can do here.

  13.     */

  14.    Fatal("Error while allocating a new PH7 engine instance");

  15.   }

  16.   /* Compile the PHP test program defined above */

  17.   rc = ph7_compile_v2(

  18.            pEngine, /* PH7 engine */

  19.            PHP_PROG, /* PHP test program */

  20.            -1 /* Compute input length automatically*/,

  21.            &pVm, /* OUT: Compiled PHP program */

  22.            0 /* IN: Compile flags */

  23.        );

  24.   if( rc != PH7_OK ){

  25.       if( rc == PH7_COMPILE_ERR ){

  26.         const char *zErrLog;

  27.         int nLen;

  28.         /* Extract error log */

  29.        ph7_config(pEngine,

  30.           PH7_CONFIG_ERR_LOG,

  31.           &zErrLog,

  32.           &nLen

  33.        );

  34.       if( nLen > 0 ){

  35.          /* zErrLog is null terminated */

  36.          puts(zErrLog);

  37.     }

  38.   }

  39.    /* Exit */

  40.    Fatal("Compile error");

  41.   }

  42.   /* Now register our constants and their associated C procedure */

  43.   rc = ph7_create_constant(pVm,"__PI__",PI_Constant,0);

  44.   if( rc != PH7_OK ){

  45.      Fatal("Error while installing the __PI__ constant");

  46.    }

  47.    rc = ph7_create_constant(pVm,"__TIME__",TIME_Constant,0);

  48.    if( rc != PH7_OK ){

  49.      Fatal("Error while installing the __TIME__ constant");

  50.    }

  51.    rc = ph7_create_constant(pVm,"__OS__",OS_Constant,0);

  52.    if( rc != PH7_OK ){

  53.      Fatal("Error while installing the __OS__ constant");

  54.    }

  55.   /*

  56.    * Configure our VM:

  57.    * Install the VM output consumer callback defined above.

  58.    */

  59.    rc = ph7_vm_config(pVm,

  60.     PH7_VM_CONFIG_OUTPUT,

  61.      Output_Consumer, /* Output Consumer callback */

  62.       0 /* Callback private data */

  63.    );

  64.   if( rc != PH7_OK ){

  65.      Fatal("Error while installing the VM output consumer callback");

  66.   }

  67.   /*

  68.    * And finally,execute our program. Note that your output

  69.   * (STDOUT in our case) should display the result.

  70.    */

  71.    ph7_vm_exec(pVm,0);

  72.    /* All done,cleanup the mess left behind.

  73.    */

  74.   ph7_vm_release(pVm);

  75.   ph7_release(pEngine);

  76.   return 0;

  77.  }

Download the C file.

We create a new PH7 engine instance using a call to ph7_init() on line 7. This is often the first PH7 API call that an application makes and is a prerequisite in order to compile PHP code using one of the compile interfaces.

We compile our PHP test program on line 17 using the ph7_compile_v2() interface.

We register our defined constants (__PI__, __TIME__ and __OS__) and their associated C procedures (PI_Constant(), TIME_Constant() and OS_Constant()) respectively on line 43,47 and 51 using the ph7_create_constant() interface.

We configure our Virtual Machine on line 59 by setting a VM output consumer callback named Output_Consumer() (Download the C file to see the implementation) which redirect the VM output to STDOUT.

And finally we execute our PHP program on line 71 using a call to ph7_vm_exec(). Your VM output should look like this:


__PI__ value: 3.1415926535898

__TIME__ value: 15:02:27

__OS__ value: UNIX


Clean-up is done on line 71 and 75 respectively via calls to ph7_vm_release() and ph7_release().

What to do next

As you can see, the constant expansion mechanism under PH7 is extremely powerful yet simple and it involves only a single call to ph7_create_constant().

The developer who understands this mechanism will have a good foundation on using the in-process extending PH7 interfaces. Now it's time to learn the more complex foreign functions creation mechanism.

Other useful links

Check out the Introduction To The PH7 C/C++ Interface for an introductory overview and roadmap to the dozens of PH7 interface functions.

A separate document, The PH7 C/C++ Interface, provides detailed specifications for all of the various C/C++ APIs for PH7. Once the reader understands the basic principles of operation for PH7, that document should be used as a reference guide.

Any questions, check the Frequently Asked Questions page or visit the Support Page for more information.


Symisc Systems
Copyright © Symisc Systems