mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
[RFC] Implement XMLReader::fromUri() and XMLReader::fromString()
This commit is contained in:
2
NEWS
2
NEWS
@@ -324,7 +324,7 @@ PHP NEWS
|
||||
|
||||
- XMLReader:
|
||||
. Declares class constant types. (Ayesh)
|
||||
. Add XMLReader::fromStream(). (nielsdos)
|
||||
. Add XMLReader::fromStream(), XMLReader::fromUri(), XMLReader::fromString(). (nielsdos)
|
||||
|
||||
- XMLWriter:
|
||||
. Add XMLWriter::toStream(), XMLWriter::toUri(), XMLWriter::toMemory(). (nielsdos)
|
||||
|
||||
@@ -629,7 +629,7 @@ PHP 8.4 UPGRADE NOTES
|
||||
RFC: https://wiki.php.net/rfc/array_find
|
||||
|
||||
- XMLReader:
|
||||
. Added XMLReader::fromStream().
|
||||
. Added XMLReader::fromStream(), XMLReader::fromUri(), XMLReader::fromString().
|
||||
RFC: https://wiki.php.net/rfc/xmlreader_writer_streams
|
||||
|
||||
- XMLWriter:
|
||||
|
||||
@@ -815,7 +815,7 @@ static bool xmlreader_valid_encoding(const char *encoding)
|
||||
}
|
||||
|
||||
/* {{{ Sets the URI that the XMLReader will parse. */
|
||||
PHP_METHOD(XMLReader, open)
|
||||
static void xml_reader_from_uri(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *instance_ce, bool use_exceptions)
|
||||
{
|
||||
zval *id;
|
||||
size_t source_len = 0, encoding_len = 0;
|
||||
@@ -856,12 +856,20 @@ PHP_METHOD(XMLReader, open)
|
||||
}
|
||||
|
||||
if (reader == NULL) {
|
||||
php_error_docref(NULL, E_WARNING, "Unable to open source data");
|
||||
RETURN_FALSE;
|
||||
if (use_exceptions) {
|
||||
zend_throw_error(NULL, "Unable to open source data");
|
||||
RETURN_THROWS();
|
||||
} else {
|
||||
php_error_docref(NULL, E_WARNING, "Unable to open source data");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == NULL) {
|
||||
object_init_ex(return_value, xmlreader_class_entry);
|
||||
if (UNEXPECTED(object_init_with_constructor(return_value, instance_ce, 0, NULL, NULL) != SUCCESS)) {
|
||||
xmlFreeTextReader(reader);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
intern = Z_XMLREADER_P(return_value);
|
||||
intern->ptr = reader;
|
||||
return;
|
||||
@@ -872,6 +880,16 @@ PHP_METHOD(XMLReader, open)
|
||||
RETURN_TRUE;
|
||||
|
||||
}
|
||||
|
||||
PHP_METHOD(XMLReader, open)
|
||||
{
|
||||
xml_reader_from_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlreader_class_entry, false);
|
||||
}
|
||||
|
||||
PHP_METHOD(XMLReader, fromUri)
|
||||
{
|
||||
xml_reader_from_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_CE_P(ZEND_THIS), true);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int xml_reader_stream_read(void *context, char *buffer, int len)
|
||||
@@ -1068,7 +1086,7 @@ XMLPUBFUN int XMLCALL
|
||||
*/
|
||||
|
||||
/* {{{ Sets the string that the XMLReader will parse. */
|
||||
PHP_METHOD(XMLReader, XML)
|
||||
static void xml_reader_from_string(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *instance_ce, bool throw)
|
||||
{
|
||||
zval *id;
|
||||
size_t source_len = 0, encoding_len = 0;
|
||||
@@ -1125,7 +1143,12 @@ PHP_METHOD(XMLReader, XML)
|
||||
ret = xmlTextReaderSetup(reader, NULL, uri, encoding, options);
|
||||
if (ret == 0) {
|
||||
if (id == NULL) {
|
||||
object_init_ex(return_value, xmlreader_class_entry);
|
||||
if (UNEXPECTED(object_init_with_constructor(return_value, instance_ce, 0, NULL, NULL) != SUCCESS)) {
|
||||
xmlFree(uri);
|
||||
xmlFreeParserInputBuffer(inputbfr);
|
||||
xmlFreeTextReader(reader);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
intern = Z_XMLREADER_P(return_value);
|
||||
} else {
|
||||
RETVAL_TRUE;
|
||||
@@ -1151,11 +1174,27 @@ PHP_METHOD(XMLReader, XML)
|
||||
if (inputbfr) {
|
||||
xmlFreeParserInputBuffer(inputbfr);
|
||||
}
|
||||
php_error_docref(NULL, E_WARNING, "Unable to load source data");
|
||||
RETURN_FALSE;
|
||||
|
||||
if (throw) {
|
||||
zend_throw_error(NULL, "Unable to load source data");
|
||||
RETURN_THROWS();
|
||||
} else {
|
||||
php_error_docref(NULL, E_WARNING, "Unable to load source data");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_METHOD(XMLReader, XML)
|
||||
{
|
||||
xml_reader_from_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlreader_class_entry, false);
|
||||
}
|
||||
|
||||
PHP_METHOD(XMLReader, fromString)
|
||||
{
|
||||
xml_reader_from_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_CE_P(ZEND_THIS), true);
|
||||
}
|
||||
|
||||
/* {{{ Moves the position of the current instance to the next node in the stream. */
|
||||
PHP_METHOD(XMLReader, expand)
|
||||
{
|
||||
|
||||
@@ -175,6 +175,8 @@ class XMLReader
|
||||
/** @return bool|XMLReader */
|
||||
public static function open(string $uri, ?string $encoding = null, int $flags = 0) {} // TODO Return type shouldn't be dependent on the call scope
|
||||
|
||||
public static function fromUri(string $uri, ?string $encoding = null, int $flags = 0): static {}
|
||||
|
||||
/** @param resource $stream */
|
||||
public static function fromStream($stream, ?string $encoding = null, int $flags = 0, ?string $documentUri = null): static {}
|
||||
|
||||
@@ -202,6 +204,8 @@ class XMLReader
|
||||
/** @return bool|XMLReader */
|
||||
public static function XML(string $source, ?string $encoding = null, int $flags = 0) {} // TODO Return type shouldn't be dependent on the call scope
|
||||
|
||||
public static function fromString(string $source, ?string $encoding = null, int $flags = 0): static {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function expand(?DOMNode $baseNode = null): DOMNode|false {}
|
||||
}
|
||||
|
||||
18
ext/xmlreader/php_xmlreader_arginfo.h
generated
18
ext/xmlreader/php_xmlreader_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 08ea43f5bbfa20407a6c1913fe3a51e99ba79fd8 */
|
||||
* Stub hash: 551324d130f9755c4c61cebb5084953fb6f539c4 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_XMLReader_close, 0, 0, IS_TRUE, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -59,6 +59,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_XMLReader_open, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLReader_fromUri, 0, 1, IS_STATIC, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLReader_fromStream, 0, 1, IS_STATIC, 0)
|
||||
ZEND_ARG_INFO(0, stream)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null")
|
||||
@@ -94,6 +100,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_XMLReader_XML, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_XMLReader_fromString, 0, 1, IS_STATIC, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, source, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_XMLReader_expand, 0, 0, DOMNode, MAY_BE_FALSE)
|
||||
ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseNode, DOMNode, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -114,6 +126,7 @@ ZEND_METHOD(XMLReader, moveToNextAttribute);
|
||||
ZEND_METHOD(XMLReader, read);
|
||||
ZEND_METHOD(XMLReader, next);
|
||||
ZEND_METHOD(XMLReader, open);
|
||||
ZEND_METHOD(XMLReader, fromUri);
|
||||
ZEND_METHOD(XMLReader, fromStream);
|
||||
ZEND_METHOD(XMLReader, readInnerXml);
|
||||
ZEND_METHOD(XMLReader, readOuterXml);
|
||||
@@ -123,6 +136,7 @@ ZEND_METHOD(XMLReader, setParserProperty);
|
||||
ZEND_METHOD(XMLReader, setRelaxNGSchema);
|
||||
ZEND_METHOD(XMLReader, setRelaxNGSchemaSource);
|
||||
ZEND_METHOD(XMLReader, XML);
|
||||
ZEND_METHOD(XMLReader, fromString);
|
||||
ZEND_METHOD(XMLReader, expand);
|
||||
|
||||
static const zend_function_entry class_XMLReader_methods[] = {
|
||||
@@ -142,6 +156,7 @@ static const zend_function_entry class_XMLReader_methods[] = {
|
||||
ZEND_ME(XMLReader, read, arginfo_class_XMLReader_read, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(XMLReader, next, arginfo_class_XMLReader_next, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(XMLReader, open, arginfo_class_XMLReader_open, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(XMLReader, fromUri, arginfo_class_XMLReader_fromUri, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(XMLReader, fromStream, arginfo_class_XMLReader_fromStream, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(XMLReader, readInnerXml, arginfo_class_XMLReader_readInnerXml, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(XMLReader, readOuterXml, arginfo_class_XMLReader_readOuterXml, ZEND_ACC_PUBLIC)
|
||||
@@ -151,6 +166,7 @@ static const zend_function_entry class_XMLReader_methods[] = {
|
||||
ZEND_ME(XMLReader, setRelaxNGSchema, arginfo_class_XMLReader_setRelaxNGSchema, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(XMLReader, setRelaxNGSchemaSource, arginfo_class_XMLReader_setRelaxNGSchemaSource, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(XMLReader, XML, arginfo_class_XMLReader_XML, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(XMLReader, fromString, arginfo_class_XMLReader_fromString, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
ZEND_ME(XMLReader, expand, arginfo_class_XMLReader_expand, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
56
ext/xmlreader/tests/fromString_custom_constructor.phpt
Normal file
56
ext/xmlreader/tests/fromString_custom_constructor.phpt
Normal file
@@ -0,0 +1,56 @@
|
||||
--TEST--
|
||||
XMLReader::fromString() - custom constructor
|
||||
--EXTENSIONS--
|
||||
xmlreader
|
||||
--FILE--
|
||||
<?php
|
||||
class CustomXMLReader extends XMLReader {
|
||||
public int $myField;
|
||||
|
||||
public function __construct() {
|
||||
$this->myField = 1234;
|
||||
echo "hello world\n";
|
||||
}
|
||||
}
|
||||
|
||||
$reader = CustomXMLReader::fromString("<root/>");
|
||||
var_dump($reader);
|
||||
var_dump($reader->read());
|
||||
var_dump($reader->nodeType);
|
||||
?>
|
||||
--EXPECTF--
|
||||
hello world
|
||||
object(CustomXMLReader)#%d (1) {
|
||||
["attributeCount"]=>
|
||||
uninitialized(int)
|
||||
["baseURI"]=>
|
||||
uninitialized(string)
|
||||
["depth"]=>
|
||||
uninitialized(int)
|
||||
["hasAttributes"]=>
|
||||
uninitialized(bool)
|
||||
["hasValue"]=>
|
||||
uninitialized(bool)
|
||||
["isDefault"]=>
|
||||
uninitialized(bool)
|
||||
["isEmptyElement"]=>
|
||||
uninitialized(bool)
|
||||
["localName"]=>
|
||||
uninitialized(string)
|
||||
["name"]=>
|
||||
uninitialized(string)
|
||||
["namespaceURI"]=>
|
||||
uninitialized(string)
|
||||
["nodeType"]=>
|
||||
uninitialized(int)
|
||||
["prefix"]=>
|
||||
uninitialized(string)
|
||||
["value"]=>
|
||||
uninitialized(string)
|
||||
["xmlLang"]=>
|
||||
uninitialized(string)
|
||||
["myField"]=>
|
||||
int(1234)
|
||||
}
|
||||
bool(true)
|
||||
int(1)
|
||||
20
ext/xmlreader/tests/fromString_custom_constructor_error.phpt
Normal file
20
ext/xmlreader/tests/fromString_custom_constructor_error.phpt
Normal file
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
XMLReader::fromString() - custom constructor with error
|
||||
--EXTENSIONS--
|
||||
xmlreader
|
||||
--FILE--
|
||||
<?php
|
||||
class CustomXMLReader extends XMLReader {
|
||||
public function __construct() {
|
||||
throw new Error('nope');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CustomXMLReader::fromString("<root/>");
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
nope
|
||||
36
ext/xmlreader/tests/fromUri_custom_constructor.phpt
Normal file
36
ext/xmlreader/tests/fromUri_custom_constructor.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
XMLReader::fromUri() - custom constructor
|
||||
--EXTENSIONS--
|
||||
xmlreader
|
||||
--FILE--
|
||||
<?php
|
||||
class CustomXMLReader extends XMLReader {
|
||||
public int $myField;
|
||||
|
||||
public function __construct() {
|
||||
$this->myField = 1234;
|
||||
echo "hello world\n";
|
||||
}
|
||||
}
|
||||
|
||||
$filename = __DIR__ . '/_fromUri_custom_constructor.xml';
|
||||
$xmlstring = '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<books></books>';
|
||||
file_put_contents($filename, $xmlstring);
|
||||
|
||||
$reader = XMLReader::fromUri($filename);
|
||||
|
||||
// Only go through
|
||||
while ($reader->read()) {
|
||||
echo $reader->name."\n";
|
||||
}
|
||||
$reader->close();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
books
|
||||
books
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . '/_fromUri_custom_constructor.xml');
|
||||
?>
|
||||
36
ext/xmlreader/tests/fromUri_custom_constructor_error.phpt
Normal file
36
ext/xmlreader/tests/fromUri_custom_constructor_error.phpt
Normal file
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
XMLReader::fromUri() - custom constructor with error
|
||||
--EXTENSIONS--
|
||||
xmlreader
|
||||
--FILE--
|
||||
<?php
|
||||
class CustomXMLReader extends XMLReader {
|
||||
public function __construct() {
|
||||
throw new Error('nope');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CustomXMLReader::fromUri("nonexistent");
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
$filename = __DIR__ . '/_fromUri_custom_constructor_error.xml';
|
||||
$xmlstring = '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<books></books>';
|
||||
file_put_contents($filename, $xmlstring);
|
||||
|
||||
try {
|
||||
CustomXMLReader::fromUri($filename);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Unable to open source data
|
||||
nope
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . '/_fromUri_custom_constructor_error.xml');
|
||||
?>
|
||||
Reference in New Issue
Block a user