#49567 [Opn]: DOM/XSL: Suggestion: registerObjectMethods()
ID: 49567 Updated by: chr...@php.net 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: Thanks for your work. Here's the right place for the patches, but you could also send it to me or to php-internals, so that it won't get forgotten :) chregu Previous Comments: [2009-09-23 09:10:33] mjs at beebo dot org Thanks for your reply. Yes, you can register exactly one object. If you call registerPHPFunctions() twice, the functions/methods registered will be those of the second object. If there's a function of the same name, it won't get called-- essentially if you have php:function('foo') in your XSL, foo() is either considered as a function in global scope (if you registered an array of strings, or nothing at all), or a method name in the "scope" of the registered object (if you registered an object). This is not the most flexible approach but I think it's a simple and straightforward enhancement that requires no extra syntax on either the PHP or XSL side. Also, anything more advanced is beyond my extension-writing capabilities! I've made a few changes to the patch, and am working on a few more little things that don't affect the syntax. Is here the right place to post it when I'm done? [2009-09-22 13:30:58] chr...@php.net Thanks for your work. I didn't test it out, but looking at the code 2 questions pop up: You can register exactly one object? and What happens, if there's a function with that name? eg. 'add' in your test? Not sure, if I'm happy how it is right now, but it certainly goes into the right direction. [2009-09-22 07:14:34] mjs at beebo dot org 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 in the XSL results in a call to $foo->quux(44). i.e. in PHP: $foo = new Foo(); $processor->registerPHPFunctions($foo); In XSL: 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-- + +--FILE-- +loadXML(""); +$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-- + +--CREDITS-- +Michael Stillwell \ 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 @@ +http://www.w3.org/1999/XSL/Transform"; + xmlns:php="http://php.net/xsl"; + exclude-result-prefixes="php"> + + + + + + + + + + \ 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(ca
#49567 [Opn]: DOM/XSL: Suggestion: registerObjectMethods()
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: Thanks for your reply. Yes, you can register exactly one object. If you call registerPHPFunctions() twice, the functions/methods registered will be those of the second object. If there's a function of the same name, it won't get called-- essentially if you have php:function('foo') in your XSL, foo() is either considered as a function in global scope (if you registered an array of strings, or nothing at all), or a method name in the "scope" of the registered object (if you registered an object). This is not the most flexible approach but I think it's a simple and straightforward enhancement that requires no extra syntax on either the PHP or XSL side. Also, anything more advanced is beyond my extension-writing capabilities! I've made a few changes to the patch, and am working on a few more little things that don't affect the syntax. Is here the right place to post it when I'm done? Previous Comments: [2009-09-22 13:30:58] chr...@php.net Thanks for your work. I didn't test it out, but looking at the code 2 questions pop up: You can register exactly one object? and What happens, if there's a function with that name? eg. 'add' in your test? Not sure, if I'm happy how it is right now, but it certainly goes into the right direction. [2009-09-22 07:14:34] mjs at beebo dot org 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 in the XSL results in a call to $foo->quux(44). i.e. in PHP: $foo = new Foo(); $processor->registerPHPFunctions($foo); In XSL: 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-- + +--FILE-- +loadXML(""); +$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-- + +--CREDITS-- +Michael Stillwell \ 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 @@ +http://www.w3.org/1999/XSL/Transform"; + xmlns:php="http://php.net/xsl"; + exclude-result-prefixes="php"> + + + + + + + + + + \ 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.
#49567 [Opn]: DOM/XSL: Suggestion: registerObjectMethods()
ID: 49567 Updated by: chr...@php.net 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: Thanks for your work. I didn't test it out, but looking at the code 2 questions pop up: You can register exactly one object? and What happens, if there's a function with that name? eg. 'add' in your test? Not sure, if I'm happy how it is right now, but it certainly goes into the right direction. Previous Comments: [2009-09-22 07:14:34] mjs at beebo dot org 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 in the XSL results in a call to $foo->quux(44). i.e. in PHP: $foo = new Foo(); $processor->registerPHPFunctions($foo); In XSL: 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-- + +--FILE-- +loadXML(""); +$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-- + +--CREDITS-- +Michael Stillwell \ 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 @@ +http://www.w3.org/1999/XSL/Transform"; + xmlns:php="http://php.net/xsl"; + exclude-result-prefixes="php"> + + + + + + + + + + \ 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;
#49567 [Opn]: DOM/XSL: Suggestion: registerObjectMethods()
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 in the XSL results in a call to $foo->quux(44). i.e. in PHP: $foo = new Foo(); $processor->registerPHPFunctions($foo); In XSL: 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-- + +--FILE-- +loadXML(""); +$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-- + +--CREDITS-- +Michael Stillwell \ 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 @@ +http://www.w3.org/1999/XSL/Transform"; + xmlns:php="http://php.net/xsl"; + exclude-result-prefixes="php"> + + + + + + + + + + \ 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->regi