How to Use HipHop Compiled Libraries in Python

1. Building a library for Python When an HipHop project is compiled with --format=lib-ffi, a SWIG .i file is generated to wrap all the top-level PHP functions, located in directory output/ffi. In output, run "make" with hphp/src/ffi/python.mk, then a python wrapper and a corresponding shared library will be created in directory output/ffi/python. For example, if your HipHop project is named phplib, after the above steps, you will get a Python wrapper phplib.py and a shared library _phplib.so, both in output/ffi/python. To use it in python, just do LD_PRELOAD="libstdc++.so.6" python >>> import phplib Then you can start using functions implemented in HipHop. Note that LD_PRELOAD is needed due to some swig related problem explained here: http://stackoverflow.com/questions/2778193/segfault-during-cxa-allocate-exception-in-swig-wrapped-library 2. Using HipHop functions in Python (1) hphpStart() This function initializes the HipHop environment, including all static variables. It only needs to be called ONCE before calling any HipHop functions. For example, phplib.hphpStart(); (2) hphpStartSession() and hphpFinishSession() The first function starts an HipHop session, within which HipHop functions are called, and HipHop objects live. It also returns a session handle (a pointer to the underlying HphpSession object) that becomes the first parameter of every HipHop function call. It also initializes global HipHop variables. The second function takes the session handle as its parameter, and finishes the session by destrying all the references to HipHop objects that have been created in the session. Therefore, after hphpFinishSession(), they Python program should NOT try to use any values generated by the HipHop library. Continue with the phplib example: s = phplib.hphpStartSession(); # calling HipHop functions phplib.hphpFinishSession(s); Each HipHop object created inside an HipHop session s will live until the time hphpFinishSession(s) is called. Therefore, a session should not create too many HipHop objects. After all, a session is not meant to run for a long time. A Python program, after calling hphpStart(), may create an arbitrary number of HipHop sessions, but two HipHop sessions must NOT overlap, at least not in the same thread. (3) Calling HipHop functions The HipHop session needs to keep track of every HipHop object created during the session in order to properly destroy them in the end. Therefore, every HipHop function wrapped in Python takes an extra parameter for the session handle. For example, if there is an HipHop function f() implemented in phplib, in Python, it is called as (s is the session handle): phplib.f(s); (4) Passing values between HipHop and Python Each HipHop value is represented as a Variant pointer, which is essentially opaque in Python. The HipHop value contained in a Variant could be one of the following 7 types: null, boolean, int (64-bit), double, string, array, or object. The library defines constants to represent each type: TypeNull, TypeBoolean, TypeInt, TypeDouble, TypeString, TypeArray, TypeObject. For example, to test whether an HipHop value v is an integer or not, one can use: if phplib.hphpGetType(v) == phplib.TypeInt: ... There are also several helper functions that can be used to create HipHop values, or to retrieve primitive values from an HipHop Variant. For example: b = phplib.hphpBoolean(s, True); # b now contains an HipHop boolean str = phplib.hphpString(s, "hello"); # creates a string in HipHop print phplib.hphpGetString(s, str); # retrieves the string back to Python a = phplib.hphpArray(s); # a contains an empty HipHop array phplib.hphpSet(s, a, b, str); # array (true => "hello") str2 = phplib.hphpGet(s, a, b); # str2 contains HipHop string "hello" There is also an hphpAppend function to add a value to the end of an HipHop array, phplib.hphpAppend(s, a, b) in Python is the same as a[] = b in PHP. Each Python value needs to be wrapped before being passed to HipHop, and each value returned by HipHop needs to be unwrapped before Python can access the value. Please see hphp/src/ffi/swig/swig.i for the definitions of all the helper functions. (5) Invoking funtions or files dynamically There are also helper functions for dynamically invoking a top-level HipHop function or including a PHP file (which must be part of the compiled library as well). phplib.hphpInvoke(s, "f", arr); # invokes the HipHop function f, # HipHop array arr contains the # arguments phplib.hphpIncludeFile(s, "lib/users.php"); # includes a compiled PHP file Moreover, all the built-in functions of PHP are also available through dynamic invocation. (6) Iteration through an HipHop array One can iterate through an HipHop array (a set of key-value pairs) with built-in helper functions: hphpIterBegin(), hphpIterAdvance(), and hphpIterValid(). For example, iter = phplib.hphpIterBegin(s, arr); # iter is an opaque pointer # to the underlying array # iterator while phplib.hphpIterValid(s, iter): key = phplib.hphpIterGetKey(s, arr, iter); # gets the key value = phplib.hphpIterGetValue(s, arr, iter); # gets the value # neither of the two getter # functions moves the # iterator ... iter = phplib.hphpIterAdvance(s, arr, iter); # advances the iterator There are also some other helper functions that help manipulate arrays. For example, a = phplib.hphpArray(s); ... len = phplib.hphpCount(s, a); # gets the size of the array key = ... b = phplib.hphpIsset(s, a, key); # checks whether a[key] is set, returns # a boolean value in Python (not an HipHop # variant) phplib.hphpUnset(s, a, key); # unsets a[key] (7) Accessing object variables Object variables are accessed through helper functions hphpSetField(), hphpGetField(), hphpIssetField(), and hphpUnsetField(). They are generally similar to their array counterparts. However, fields are named with Python strings, but array keys are HipHop variants. For example, a = phplib.hphpNewObject(s, "A", args); # creates an object of type A v = phplib.hphpGetField(s, a, "f"); # gets a->f v2 = ... phplib.hphpSetField(s, a, "f", v2); # a->f = v2 phplib.hphpIssetField(s, a, "f"); # should return TRUE now phplib.hphpUnsetField(s, a, "f"); # unsets the field f (8) Manipulating global variables Global variables are accessed with helper functions hphpGetGlobal() and hphpSetGlobal(). For example, a = phplib.hphpGetGlobal(s, "_SERVER"); # gets a copy of the global variable # $_SERVER phplib.hphpSet(s, a, "SRC", "/"); # $_SERVER['SRC'] NOT updated yet phplib.hphpSetGlobal(s, "_SERVER", a); # $_SERVER updated Note that the value obtained with hphpGetGlobal() is logically just a copy of the global variable, and it takes a call to hphpSetGlobal() to really update the value of the global variable.