xml_set_object

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

xml_set_object在对象中使用 XML 解析器

描述

xml_set_object(XMLParser $parser, object $object): true

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

参数

parser

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

object

使用 XML 解析器的对象。

返回值

始终返回 true

变更日志

版本 描述
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
18 年前
经过大量文档搜索,我终于成功地让 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
19 年前
补充一下下面“lmfe at mega dot ist dot utl dot pt”的贡献,我不得不承认,如果对象的 MemberVars 没有在构造函数中初始化,那么这种行为在 PHP 中是非常普遍的。
到目前为止,对我来说最有效的方法是这样的
<?php
class foo {
var
$bar
// 构造函数
function foo() {
unset(
$this->bar); // 每次实例化,变量都会被清除
}
}
?>
lmfe at mega dot ist dot utl dot pt
19 年前
使用 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
20 年前
关于创建抽象的“回调处理程序”的说明,如其他一些笔记中提到的。在这种情况下,我建议扩展基本 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
23 年前
在对象中使用 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
21 年前
在示例中像这样传递对象作为调用时引用 (&$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_set_object 非常棒,如果你想在 xml 类中硬编码你的 start_element、end_element 等函数。

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

解决方案是创建一个通用的 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
22 年前
<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
23 年前
除非在您的 INI 文件中将 allow_call_time_pass_reference 设置为 true,否则该示例将生成警告。它也不接受按值调用。
robert at webmotion dot com
24 年前
虽然 PHP 类对象没有自动析构函数,但创建名为 destroy 的方法并手动执行析构非常简单。在上面的示例中,可能不需要立即释放 XML 解析器... 从示例中可以看出,该对象是可重复使用的。
To Top