PHP 变量作用域和“foreach”
我的应用程序正在构建 PDF 文档。它使用脚本来生成每个页面的 HTML。 PDF 生成类是“Production”,页面类是“Page”。
class Production
{
private $_pages; // an array of "Page" objects that the document is composed of
public getPages()
{
return $this->_pages;
}
public render()
{
foreach($this->_pages as $page) {
$pageHtml = $page->getHtml($this); // Page takes a pointer to production to access some of its data.
}
}
}
以下是 Page 类摘要:
class Page
{
private $scriptPath; // Path to Script File (PHP)
public function getHtml(Production &$production)
{
$view = new Zend_View();
$view->production = $production;
return $view->render($this->scriptPath);
}
}
我在对目录进行编码时遇到了问题。它访问 Production,获取所有页面,查询它们,并根据页面标题构建 TOC:
// TableOfContents.php
// "$this" refers to Zend_View from Pages->getHtml();
$pages = $this->production->getPages();
foreach($pages as $page) {
// Populate TOC
// ...
// ...
}
发生的情况是 TableOfContents.php 中的 foreach 干扰 Production 中的 foreach。生产 foreach 循环在索引页(实际上是文档中的第二页,在封面页之后)终止。
文档布局如下:
1)封面
2)目录
3)页面 A
4)页面 B
5)页面 C
TableOfContents.php 在其 foreach 循环中,根据需要遍历页面并构建整个页面的索引文档,但 Production 中的循环在目录处终止,并且不会继续渲染页面 A、B 和 C。
如果我从 TableOfContents.php 中删除 foreach,则所有连续页面都会正确渲染。
我觉得这是指针和变量作用域的问题,那么我该怎么解决呢?
My application is building PDF documents. It uses scripts to produce each page's HTML.
The PDF-Generating class is "Production", and page class is "Page".
class Production
{
private $_pages; // an array of "Page" objects that the document is composed of
public getPages()
{
return $this->_pages;
}
public render()
{
foreach($this->_pages as $page) {
$pageHtml = $page->getHtml($this); // Page takes a pointer to production to access some of its data.
}
}
}
Here is the Page class summary:
class Page
{
private $scriptPath; // Path to Script File (PHP)
public function getHtml(Production &$production)
{
$view = new Zend_View();
$view->production = $production;
return $view->render($this->scriptPath);
}
}
I've encountered a problem when coding Table of Contents. It accesses Production, get all the pages, queries them, and builds TOC based on page titles:
// TableOfContents.php
// "$this" refers to Zend_View from Pages->getHtml();
$pages = $this->production->getPages();
foreach($pages as $page) {
// Populate TOC
// ...
// ...
}
What happens is that foreach inside the TableOfContents.php is interfering with foreach in Production. Production foreach loop is terminated at Index page (which is actually a second page in the document, after the cover page).
The Document Layout is like so:
1) Cover Page
2) Table of Contents
3) Page A
4) Page B
5) Page C
TableOfContents.php, in its foreach loop, goes through the pages as required and builds an index of the entire document, but the loop in Production terminates at Table of Contents and does not proceed to render Pages A, B and C.
If I remove foreach from TableOfContents.php, all consecutive pages are rendered appropriately.
I feel it's a problem with the pointer and variable scope, so what can I do to fix it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
诊断
我怀疑问题是
$_pages
不是一个普通的 PHP 数组,而是一个恰好实现迭代器
接口。因此,foreach 循环的“状态”存储在对象本身上,这意味着两个循环是冲突的。如果
$_pages
是一个普通数组,那么就不会有问题,因为$pages = $this->product->getPages();
行会使复制,因为 PHP 数组是在赋值时复制的(与对象不同),而且还因为普通数组上的嵌套foreach
循环不存在这个问题。 (大概来自一些内部数组复制/分配逻辑。)解决方案
“快速而肮脏”的修复是为了避免 foreach 循环,但我认为这既令人烦恼,又会成为未来错误的原因,因为很容易忘记
$_pages
需要超级特殊的处理。对于真正的修复,我建议查看 $_pages 中对象后面的类,看看是否可以更改该类。不要让
$_pages
成为迭代器,而是更改$_pages
以便它提供 > 通过IteratorAggregate
的迭代器界面。这样,每个 foreach 循环都需要一个单独的迭代器对象并维护单独的状态。
下面是一个示例脚本来说明该问题,部分抄袭自 PHP 参考页:
Diagnosis
I suspect the problem is that
$_pages
isn't a normal PHP array, but instead an object which happens to implement theIterator
interface. Because of this, the "state" of the foreach loop is stored on the object itself, which means that the two loops are conflicting.If
$_pages
was a plain array, then there would be no problem, since the line$pages = $this->production->getPages();
would make a copy, since PHP arrays are copied on assignment (unlike objects) and also because nestedforeach
loops on a normal array don't have that problem. (Presumably from some internal array copy/assignemnt logic.)Solution
The "fast and dirty" fix is to avoid foreach loops, but I think that would be both annoying and be a cause of future bugs because it's very easy to forget that
$_pages
needs super-special treatment.For a real fix, I suggest looking at whatever class is behind the object in
$_pages
and see if you can change that class. Instead of having$_pages
be theIterator
, change$_pages
so that it provides iterators through theIteratorAggregate
interface.That way every
foreach
loop asks for a separate iterator object and maintains separate state.Here is a sample script to illustrate the problem, partially cribbed from the PHP reference pages:
我不确定你的问题是什么,但你可以看看 PHP 函数
reset
< /a> =)I'm not sure to understand what is your problem, but you may look at the PHP function
reset
=)解决方案是避免使用 foreach 并使用传统循环,如下所示:
PHP 中的嵌套 foreach 问题
The solution was the avoid using foreach and use conventional loops, as suggested here:
nested foreach in PHP problem