
<h2>How to Use HipHop Compiled Libraries in Python</h2>

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
<b>output/ffi</b>. In <b>output</b>, run "make" with
<b>hphp/src/ffi/python.mk</b>, then a python wrapper and a corresponding
shared library will be created in directory <b>output/ffi/python</b>.

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 <b>output/ffi/python</b>. 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 <b>hphp/src/ffi/swig/swig.i</b> 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.
