From dc3766002580190a5c7acf597532d551501847ca Mon Sep 17 00:00:00 2001 From: Joe Afflerbach Date: Thu, 21 May 2026 10:19:40 +0200 Subject: [PATCH] ext/dom: Return numeric results from XPath callbacks as numbers not as string see https://www.w3.org/TR/xpath-10/#numbers --- .../modern/xml/return_scalars_from_xpath.phpt | 25 +++++++++++++++++++ ext/dom/xpath_callbacks.c | 4 +++ 2 files changed, 29 insertions(+) create mode 100644 ext/dom/tests/modern/xml/return_scalars_from_xpath.phpt diff --git a/ext/dom/tests/modern/xml/return_scalars_from_xpath.phpt b/ext/dom/tests/modern/xml/return_scalars_from_xpath.phpt new file mode 100644 index 000000000000..a3b0b0a2d683 --- /dev/null +++ b/ext/dom/tests/modern/xml/return_scalars_from_xpath.phpt @@ -0,0 +1,25 @@ +--TEST-- +Returning scalar values from Dom\XPath callback +--EXTENSIONS-- +dom +--FILE-- +'); +$xpath = new Dom\XPath($dom); +$xpath->registerPhpFunctionNs('urn:x', 'get-int', fn(): int => 42); +$xpath->registerPhpFunctionNs('urn:x', 'get-float', fn(): float => 4.2); +$xpath->registerPhpFunctionNs('urn:x', 'get-string', fn(): string => "test"); +$xpath->registerPhpFunctionNs('urn:x', 'get-bool', fn(bool $b): bool => $b); +$xpath->registerNamespace('x', 'urn:x'); +var_dump($xpath->evaluate('x:get-int()')); +var_dump($xpath->evaluate('x:get-float()')); +var_dump($xpath->evaluate('x:get-string()')); +var_dump($xpath->evaluate('x:get-bool(1)')); +var_dump($xpath->evaluate('x:get-bool(0)')); +?> +--EXPECT-- +float(42) +float(4.2) +string(4) "test" +bool(true) +bool(false) diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c index 90395dc15f2e..c659359d67fc 100644 --- a/ext/dom/xpath_callbacks.c +++ b/ext/dom/xpath_callbacks.c @@ -438,6 +438,10 @@ static zend_result php_dom_xpath_callback_dispatch(php_dom_xpath_callbacks *xpat valuePush(ctxt, xmlXPathNewNodeSet(nodep)); } else if (Z_TYPE(callback_retval) == IS_FALSE || Z_TYPE(callback_retval) == IS_TRUE) { valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(callback_retval) == IS_TRUE)); + } else if (Z_TYPE(callback_retval) == IS_LONG) { + valuePush(ctxt, xmlXPathNewFloat(Z_LVAL(callback_retval))); + } else if (Z_TYPE(callback_retval) == IS_DOUBLE) { + valuePush(ctxt, xmlXPathNewFloat(Z_DVAL(callback_retval))); } else if (Z_TYPE(callback_retval) == IS_OBJECT) { zend_type_error("Only objects that are instances of DOM nodes can be converted to an XPath expression"); zval_ptr_dtor(&callback_retval);