ID: 49567 User updated by: mjs at beebo dot org Reported By: mjs at beebo dot org Status: Open Bug Type: Feature/Change Request Operating System: OS X PHP Version: 5.3.0 New Comment:
Had a look at how the xsl extension works, and had a shot at implementing this myself--the patch is below. Instead of adding a new function I enhanced registerPHPFunctions() so that it can take an object. It works like this: if an object is provided (say $foo), then <xsl:value-of select="php:function('quux', 44)"/> in the XSL results in a call to $foo->quux(44). i.e. in PHP: $foo = new Foo(); $processor->registerPHPFunctions($foo); In XSL: <xsl:value-of select="php:function('quux', 44)"/> Two of the tests in ext/xsl failed, but they fail without this patch also. The patch is: Index: ext/xsl/tests/xsltprocessor_registerPHPFunctions-method.phpt =================================================================== --- ext/xsl/tests/xsltprocessor_registerPHPFunctions-method.phpt (revision 0) +++ ext/xsl/tests/xsltprocessor_registerPHPFunctions-method.phpt (revision 0) @@ -0,0 +1,38 @@ +--TEST-- +Checks XSLTProcessor::registerPHPFunctions($obj) where the "functions" +exposed in the XSL file are methods of $obj. +--SKIPIF-- +<?php +if (!extension_loaded('xsl')) { + die("skip\n"); +} +?> +--FILE-- +<?php + +class Foo { + public function greet($name) { + return "Hello, $name"; + } + public function add($i, $j) { + return $i + $j; + } +} + +$xml = new DOMDocument(); +$xml->loadXML("<root/>"); +$xsl = new DOMDocument(); +$xsl->load(dirname(__FILE__) . "/phpmethod.xsl"); + +$proc = new XSLTProcessor(); +$proc->importStylesheet($xsl); + +$foo = new Foo(); + +$proc->registerPHPFunctions($foo); + +echo $proc->transformToXml($xml); +--EXPECTF-- +<result greet="Hello, Clem" add="7"/> +--CREDITS-- +Michael Stillwell <m...@beebo.org> \ No newline at end of file Index: ext/xsl/tests/phpmethod.xsl =================================================================== --- ext/xsl/tests/phpmethod.xsl (revision 0) +++ ext/xsl/tests/phpmethod.xsl (revision 0) @@ -0,0 +1,15 @@ +<xsl:stylesheet + version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:php="http://php.net/xsl" + exclude-result-prefixes="php"> + <xsl:output omit-xml-declaration="yes"/> +<xsl:template match="/"> + <result> + <!-- pass a single string argument --> + <xsl:attribute name="greet"><xsl:value-of select="php:function('greet', 'Clem')"/></xsl:attribute> + <!-- pass two integer arguments --> + <xsl:attribute name="add"><xsl:value-of select="php:function('add', 3, 4)"/></xsl:attribute> + </result> +</xsl:template> +</xsl:stylesheet> \ No newline at end of file Index: ext/xsl/php_xsl.h =================================================================== --- ext/xsl/php_xsl.h (revision 288545) +++ ext/xsl/php_xsl.h (working copy) @@ -55,6 +55,7 @@ HashTable *node_list; php_libxml_node_object *doc; char *profiling; + zval *object_ptr; } xsl_object; void php_xsl_set_object(zval *wrapper, void *obj TSRMLS_DC); Index: ext/xsl/xsltprocessor.c =================================================================== --- ext/xsl/xsltprocessor.c (revision 288545) +++ ext/xsl/xsltprocessor.c (working copy) @@ -308,11 +308,11 @@ fci.function_name = &handler; fci.symbol_table = NULL; - fci.object_ptr = NULL; fci.retval_ptr_ptr = &retval; fci.no_separation = 0; + fci.object_ptr = intern->object_ptr ? intern->object_ptr : NULL; /*fci.function_handler_cache = &function_ptr;*/ - if (!zend_make_callable(&handler, &callable TSRMLS_CC)) { + if ((intern->registerPhpFunctions != 3) && !zend_make_callable(&handler, &callable TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", callable); } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable, strlen(callable) + 1) == 0) { @@ -320,6 +320,9 @@ /* Push an empty string, so that we at least have an xslt result... */ valuePush(ctxt, xmlXPathNewString("")); } else { + if (intern->object_ptr) { + fci.object_ptr = intern->object_ptr; + } result = zend_call_function(&fci, NULL TSRMLS_CC); if (result == FAILURE) { if (Z_TYPE(handler) == IS_STRING) { @@ -794,6 +797,7 @@ zval *id; xsl_object *intern; zval *array_value, **entry, *new_string; + zval *obj_ptr; int name_len = 0; char *name; @@ -823,6 +827,12 @@ zend_hash_update(intern->registered_phpfunctions, name, name_len + 1, &new_string, sizeof(zval*), NULL); intern->registerPhpFunctions = 2; + } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj_ptr) == SUCCESS) { + intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); + zend_hash_clean(intern->registered_phpfunctions); + intern->object_ptr = obj_ptr; + Z_ADDREF_P(obj_ptr); + intern->registerPhpFunctions = 3; } else { intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); intern->registerPhpFunctions = 1; Index: ext/xsl/php_xsl.c =================================================================== --- ext/xsl/php_xsl.c (revision 288545) +++ ext/xsl/php_xsl.c (working copy) @@ -84,6 +84,10 @@ zend_hash_destroy(intern->registered_phpfunctions); FREE_HASHTABLE(intern->registered_phpfunctions); + if (intern->object_ptr) { + Z_DELREF_P(intern->object_ptr); + } + if (intern->node_list) { zend_hash_destroy(intern->node_list); FREE_HASHTABLE(intern->node_list); @@ -127,6 +131,7 @@ intern->node_list = NULL; intern->doc = NULL; intern->profiling = NULL; + intern->object_ptr = NULL; zend_object_std_init(&intern->std, class_type TSRMLS_CC); zend_hash_copy(intern->std.properties, &class_type- >default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); Previous Comments: ------------------------------------------------------------------------ [2009-09-15 23:07:04] mjs at beebo dot org Description: ------------ A suggestion: it would be useful if there was a registerObjectMethods() that worked in a similar way to registerPHPFunctions() except that it took an object upon which methods could be called. i.e. something like class Greet { public function byName($name) { return "Hello, $name"; } } $xml = DOMDocument::loadXML("<root/>"); $xsl = DOMDocument::loadXML("... <xsl:value-of select="php:call('byName', 'Michael')"/> ..."); $proc = new XSLTProcessor(); $proc->registerObjectMethods(new Greet()); $proc->importStyleSheet($xsl); echo $proc->transformToXML($xml); ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=49567&edit=1