I am posting code for calling almost any python function from php, because it seems generally useful. Please feel free to suggest improvements or tell me this has already been done better somewhere else, etc. My limited searching turned up nothing.
I work in a heterogeneous environment with php web pages and python modules/scripts. This code requires no no creation of an ad hoc command line interface to the python module and/or ad hoc serialization of inputs and outputs. Essentially it requires python's ability to call functions with keyword arguments, dynamic importing of modules, and a serialization protocol shared by php and python. In this case I use php serialization, but perhaps YAML or JSON could be used instead. Below is the php function. It simply serializes an array of keyword parameter values, invokes the python module which will call the function (passing in the keywords) and unserializes the output. runCommand() is a helper function that simply invokes the command, passes it stdin, and returns stdout, stderr, and the exit code of the command. function python_dispatch($fullyQualifiedFuncName, $keywords) { $stdin = serialize($keywords); $cmd = PYTHON_ROOT."/php_dispatch.py ".escapeshellarg($fullyQualifiedFuncName); list($exitcode, $stdout, $stderr) = runCommand($cmd, $stdin); $retval = unserialize($stdout); return array($retval, $exitcode); } The python code is not complicated either. It depends on PHPSerialize.py and PHPUnserialize.py by Scott Hurring (http://hurring.com/code/python/serialize/). There are two functions for dynamically importing the right module and traversing the components of a complete function path, like 'mypackage.mymodule.myclass.myfunc'. # this function is from http://docs.python.org/lib/built-in-funcs.html def _dispatch_import(name): mod = __import__(name) components = name.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod def _dispatch_lookup_function(name, namespace, prefix=''): # last name in component if name.find('.') == -1: return namespace[name] else: # get next component in name, and its fully qualified component name first, rest = name.split('.', 1) if prefix: modName = '.'.join([prefix, first]) else: modName = first if first in namespace: # if component is in namespace, look for the function in the namespace of the component return _dispatch_lookup_function(prefix=modName, name=rest, namespace=vars(namespace[first])) else: # else import component (using fully qualified name) and look for function in the imported component. module = _dispatch_import(modName) return _dispatch_lookup_function(prefix=modName, name=rest, namespace=vars(module)) def main(): import sys modAndFuncName = sys.argv[1] func = _dispatch_lookup_function(modAndFuncName, globals()) # reconstruct function keyword arguments from serialized input keywords = walkPHPArrayConvertHeuristically(PHPUnserialize.PHPUnserialize().unserialize(sys.stdin.read())) sys.stdin.close() retval = PHPSerialize.PHPSerialize().serialize(func(**keywords)) sys.stdout.write(retval) The last piece of the puzzle is walkPHPArrayConvertHeuristically() which converts unserialized dicts to lists if they should be lists. This hack gets around the fact that everything is a dict (a.k.a. array) in php, so using php serialization to go between php and python is not isomorphic. This might be a good reason to use JSON or YAML for serialization, but I do not have any experience with them. def walkPHPArrayConvertHeuristically(data): if type(data) is types.DictType: if isPHPDataListGuess(data): lst = convertPHPArrayToList(data) return [walkPHPArrayConvertHeuristically(item) for item in lst] else: for k in data: data[k] = walkPHPArrayConvertHeuristically(data[k]) return data else: return data def convertPHPArrayToList(array): keys = array.keys() keys.sort() return [array[k] for k in keys] def isPHPDataListGuess(data): if type(data) is types.DictType: i = 0 for k in data.keys(): if k != i: return False i += 1 return True else: return False I hope you find this code useful or interesting. Cheers, Todd -- http://mail.python.org/mailman/listinfo/python-list