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 <[email protected]>
\ 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