PHP Conference Japan 2024

xml_set_object

(PHP 4, PHP 5, PHP 7, PHP 8)

xml_set_object在对象中使用 XML 解析器

警告

此函数自 PHP 8.4.0 起已 弃用。强烈建议不要依赖此函数。

描述

#[\Deprecated]
xml_set_object(XMLParser $parser, object $object): true

此函数允许在 object 内使用 parser。所有回调函数都可以使用 xml_set_element_handler() 等设置,并假定为 object 的方法。

参数

parser

要在对象内部使用的 XML 解析器的引用。

object

使用 XML 解析器的对象。

返回值

始终返回 true

变更日志

版本 描述
8.4.0 此函数现已弃用,请改用适当的 callable 值传递给 xml_set_()
8.0.0 parser 现在期望一个 XMLParser 实例;以前,期望一个有效的 xml resource

示例

示例 #1 xml_set_object() 示例

<?php
class CustomXMLParser
{
private
$parser;

function
__construct()
{
$this->parser = xml_parser_create();

xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, "tag_open", "tag_close");
xml_set_character_data_handler($this->parser, "cdata");
}

function
parse($data)
{
xml_parse($this->parser, $data);
}

function
tag_open($parser, $tag, $attributes)
{
var_dump($tag, $attributes);
}

function
cdata($parser, $cdata)
{
var_dump($cdata);
}

function
tag_close($parser, $tag)
{
var_dump($tag);
}
}

$xml_parser = new CustomXMLParser();
$xml_parser->parse("<A ID='hallo'>PHP</A>");
?>

以上示例将输出

string(1) "A"
array(1) {
  ["ID"]=>
  string(5) "hallo"
}
string(3) "PHP"
string(1) "A"

添加注释

用户贡献的注释 17 条注释

wake dot shinigami at gmail dot com
19 年前
我终于设法让 xml_set_object() 工作了,经过大量的文档搜索。正如我找到的解决方案所暗示的那样,重点一直是错误的。

在获取包含在类中的 XML 解析器以对实例成员进行更改方面存在许多问题。这是因为,我猜测,这些函数正在使用类的新的匿名实例或类的未实例化版本。

我们要确保它做的是解析器访问其处理程序作为类的特定实例的成员方法。这可以通过使用数组方法传递回调来完成,将对象设置为对该实例的引用。这样,您就知道解析器将正确调用该函数。

例如
<?php
class Parser {

private
$parser;
private
$data;

public function
__construct() {
$this->parser = NULL;
$this->data = '';
}

private function
ParseElementStart($parser, $name, $attrs) {
// 代码
}
private function
ParseElementEnd($parser, $name) {
// 代码
}

public function
Parse($XMLdata) {
$this->parser = xml_parser_create();
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser,
array(&
$this, 'ParseElementStart'),
array(&
$this, 'ParseElementEnd'));
xml_parse($this->parser, $XMLdata);
xml_parser_free($this->parser);
}
}
?>

这样,当您调用Parse方法时,该实例中的数据可以被修改。我不确定当使用数组回调时,xml_set_object是否变得不必要,但我将其保留下来以确保xml_parse函数知道它在对象中。

如上所述,出于内存考虑,我建议在同一个函数中创建、使用和释放XML解析器,以确保所有内容都正确清理。
bettmenn at gmx dot de
20年前
补充“lmfe at mega dot ist dot utl dot pt”下面的贡献,我不得不说,如果对象的成员变量没有在构造函数中初始化,这种行为在PHP中非常常见。
到目前为止,对我来说最有效的方法是这样的
<?php
class foo {
var
$bar
// 构造函数
function foo() {
unset(
$this->bar); // 每次实例化时,变量都会被清除
}
}
?>
lmfe at mega dot ist dot utl dot pt
20年前
使用PHP 4.3.0,我得到了这种奇怪的行为

<?php
class xml {

/* (如上面文档中所述) */

} // xml类的结束

/* 此代码有效 */
$xml_parser = new xml();
$xml_parser->parse("<A ID='hallo'>PHP</A>");

/* 此代码有效 */
$xml_parser2 = new xml();
$xml_parser2->parse("<A ID='hallo2'>PHP2</A>");

/* 此代码无效 */
$xml_parser = new xml();
$xml_parser->parse("<A ID='hallo3'>PHP3</A>");
?>

在第三段代码中,php抱怨找不到它需要的处理程序。
似乎只有当变量被使用多次时才会发生此问题。
调用xml_parser_free无济于事
zitan at mediasculpt dot net
21年前
关于创建一些其他注释中提到的抽象“回调处理程序”的说明。在这种情况下,我建议扩展基本XML类并覆盖处理程序方法。我想要这样做的原因是,如果您有一个单独的回调方法类,它会导致问题,例如,如果您想从XML文件中收集信息并将其存储在一个数组中。您可以使用全局变量来解决它,但我更喜欢仅在需要时才使用它们;)

示例

<?php
class xml_output extends xml{

var
$output = array();

function
xml_output(){
$this->xml();
}

// 覆盖基本方法
function tag_open($parser, $tag, $attributes)
{
array_push($this->output, "<$tag, attributes>");
}

function
cdata($parser, $cdata)
{
array_push($this->output, "$cdata");
}

function
tag_close($parser, $tag)
{
array_push($this->output, "</$tag>");
}

}

$xml_parser = & new xml_output();
$xml_parser->parse("<A ID='hallo'>PHP</A>");
echo(
"$xml_parser->output");
?>
i_sofer at yahoo dot com
24年前
在对象中使用xml解析器似乎存在一个问题,即修改后的值(即使是对象本身的值)在解析结束时就会丢失...
joey at gimo dot co dot uk
8年前
当[$object_instance, "method_name"]是可调用时,此函数似乎用途非常有限。
hwheinzen at t-online dot de
20年前
(补充zitan的说明)
为回调处理程序类提供输出函数似乎也很容易。

示例

<?php
class CallBack {
var
$name = 'Callback';
var
$info = 'Information!';
function
toString() {
return
$this->name.': '.$this->info;
}
}
class
Main {
var
$name = 'Main';
var
$callBackObject;
function
setCallBack(&$cBIn) { $this->callBackObject = $cBIn; }
function
toString() {
return
$this->name.': '.$this->callBackObject->toString();
}
}

$cb = & new CallBack;
$m = & new Main;
$m->setCallBack(&$cb);
echo
$cb->toString();
echo
$m->toString();
?>

因此,在回调处理程序类中(例如在tag_close()中)在解析操作期间收集信息后,可以检索它们。
sbeam at syxyz dot net
22年前
像示例中那样将对象作为调用时引用传递(&$this)将在php 4.1+中产生警告。改为传递xml_set_object($xp,$this);。这似乎没有破坏任何东西 - 但我不确定。
chiefgeek at ecodedesign.com
22年前
关于我上面写的示例,补充一点说明。它需要一些改进。

因为 PHP 默认情况下是按值传递,当你像这样传递一个数组时
array($callback_handler, 'handler_method')
PHP 会复制 callback_handler 对象并使用副本中的 handler_method 方法。

由于很多原因,这不是理想的情况……这里我就不详细说明了……但你现在应该有所了解。

解决这个问题的最佳方法是更改一些内容。在函数声明中,将参数从 $callback_handler 更改为 &$callback_handler。所以现在你的声明应该如下所示

function set_callback_handler(&$callback_handler)
{
...
}

现在每次引用 $callback_handler 时,都将其更改为 &$callback_handler。例如

xml_set_element_handler(
$this->xml_parser,
array(&$callback_handler, 'start_element'),
array(&$callback_handler, 'close_Element' ));

这确保了 PHP 将始终使用同一个对象。
chiefgeek at ecodedesign.com
22年前
如果你想在你的 XML 类中硬编码 start_element、end_element 等函数,那么 xml_set_object 非常有用。

但是,如果你想提高应用程序的模块化程度呢?

解决方案是,创建一个通用的 XMLParser 类来处理除了回调函数之外的所有内容。然后创建一个抽象的 XMLCallbackHandler 类,你可以扩展它来提供任何你想要的自定义功能。

那么,如何告诉 PHP 的 xml_parser 你想使用这个其他类来处理回调函数呢?

xml_set_object?只有当函数位于你调用此方法的对象内部时,此方法才有效。

解决方案在于 xml_set_element_handler() 函数。
看看这个示例源代码……

class XMLParser
{

...

function set_callback_handler($callback_handler)
{
// 分配 startElement 和 endElement 函数
xml_set_element_handler(
$this->xml_parser,
array($callback_handler, 'start_element'),
array($callback_handler, 'close_Element' ));

/* 通过传递一个包含 ($object, 'function_name') 结构的数组
到第二个和第三个参数。我们可以告诉解析器
在另一个对象中查找这些回调函数。
*/

// 分配字符数据函数
xml_set_character_data_handler(
$this->xml_parser,
array($callback_handler, 'character_data'));
}
}

class myCallBackHandler
{
function start_element(...)
{
// 代码在此处
}

function end_element(...)
{
// 代码在此处
}

function character_data(...)
{
// 代码在此处
}
}

现在剩下的就是使用这些类了……

$parser = new XMLParser();
$parser->set_callback_handler(new myCallbackHandler());
dfoesch at cs dot nmsu dot edu
22年前
对 $xml = & new xml(); 的英文解释

好的,当 PHP 执行 "new xml()" 时,它会创建一个匿名变量(一个你无法用任何名称引用的变量),然后在其上运行构造函数。好的,现在一旦完成,它就会在上面的示例中按值赋值。这意味着指向你的解析器的那个可爱的指针指向的是类的匿名实例,而不是类的已用实例……从而使你所有变量的“影子”,解析器内部的赋值访问与解析器外部不同的变量。PHP _应该_ 做的事情(类似于 C++)是让这个语句执行,以便按引用进行赋值,以便你将新名称分配给实际构建的类,而不仅仅是你构建的类的副本。

如果他们做对了,这段代码就不会出问题了。
Anonymous
22年前
调用时按引用传递已被弃用,因此该示例存在错误,正如之前提到的那样。但是从 4.04 版(我认为)开始,“new”可以按引用返回对象。所以既要在构造函数中初始化解析器,又要将结果保存在你的对象中的干净方法是

$xml_parser = & new xml();

参见 https://php.net/manual/en/language.oop.newref.php

Ivan
pete dot nelson at serverSXPYAZMsolved dot com
23 年前
<p>回复 jon9mm 的问题,我遇到了同样的问题(函数“startElement”不存在)。我最终找到了解决方法,通过重新阅读这个 xml_set_object 文档。你必须在你的解析器函数中使用 xml_set_object($this->parser, &$this)。</p> <p>当该函数被调用时,你的对象会临时变成解析器对象并共享作用域(因此它可以看到“startElement”等)。一旦该函数完成,xml_set_object(...) 调用就会超出作用域,并且你的对象不再绑定到解析器。所以最简单的解决方案是在同一个函数中调用 xml_set_object(...),执行任何解析,然后调用 xml_parser_free(...)。</p>
<p>请记住,不要在你的对象的构造函数中调用 xml_set_object(...) - 你的对象将永远绑定到解析器对象,并且你将失去对你的对象成员函数的所有访问权限。</p>
<p>以上示例中都解释了这一点,但我需要阅读几次才能理解所有内容是如何运作的。</p>
nick at category4 dot com
23 年前
如果你在对象中使用 XML 解析器,请注意不要意外调用对象中不存在的任何方法。PHP 不会抱怨缺少的方法不存在,而是会说它无法找到处理程序例程,即使你已正确指示了它们。(FreeBSD 上的 PHP 4.0.5 版)。
williams at cse dot unl dot edu
23 年前
如果在对象的构造函数中没有调用 xml_set_object,则解析器修改的值将被保存。否则,这些值似乎不会像上面“i_sofer”所说的那样被保存。
--- 示例代码开始 ---
class foo {
var xmlparser;
function foo() { \\构造函数
$this->xmlparser=xmlparser_create();
}
function parse() {
xml_set_object($this->xmlparser,&$this);
\\也包含数据处理程序
\\以及元素处理程序
}
}
--- 示例代码结束 ---
malcontent at msgto dot com
24年前
除非在你的 INI 文件中将 allow_call_time_pass_reference 设置为 true,否则该示例将生成警告。它也不接受按值调用。
robert at webmotion dot com
24年前
虽然 PHP 类对象没有自动析构函数,但创建名为 destroy 的方法并手动执行销毁非常简单。在上面的示例中,可能不需要立即释放 XML 解析器……从示例中可以看出,该对象是可重用的。
To Top