1
0
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:
Niels Dossche
2024-06-27 22:28:50 +02:00
parent c24b8fe616
commit 4cab7f90a1
9 changed files with 218 additions and 11 deletions

2
NEWS
View File

@@ -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)

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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 {}
}

View File

@@ -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
};

View 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)

View 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

View 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');
?>

View 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');
?>