By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,866 Members | 1,660 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,866 IT Pros & Developers. It's quick & easy.

php to python dynamic dispatch example

P: n/a
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.PH PUnserialize().unserialize(sys.stdin.read()))
sys.stdin.close()

retval = PHPSerialize.PHPSerialize().serialize(func(**keywo rds))

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

Dec 18 '05 #1
Share this question for a faster answer!
Share on Google+

This discussion thread is closed

Replies have been disabled for this discussion.