ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

PHP可变范围和“foreach”

2019-06-30 16:17:57  阅读:273  来源: 互联网

标签:php scope pointers zend-framework zend-view


我的应用程序是构建PDF文档.它使用脚本来生成每个页面的HTML.
PDF-Generating类是“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干扰了生产中的foreach.生产foreach循环终止于索引页面(实际上是封面页之后的文档中的第二页).

文档布局是这样的:

1)封面

2)目录

3)页面A.

4)页面B.

5)页面C.

TableOfContents.php,在其foreach循环中,根据需要遍历页面并构建整个文档的索引,但生产中的循环终止于目录,不会继续呈现页面A,B和C.

如果我从TableOfContents.php中删除foreach,则会正确呈现所有连续页面.

我觉得这是指针和变量范围的问题,所以我该怎么做才能修复它?

解决方法:

诊断

我怀疑问题是$_pages不是普通的PHP数组,而是碰巧实现Iterator interface的对象.因此,foreach循环的“状态”存储在对象本身上,这意味着两个循环是冲突的.

如果$_pages是一个普通数组,那么就没有问题,因为行$pages = $this-> production-> getPages();会复制,因为PHP数组在赋值时复制(与对象不同),也因为普通数组上的嵌套foreach循环没有这个问题. (可能来自一些内部数组复制/辅助逻辑.)

“快速和肮脏”的修复是为了避免foreach循环,但我认为这既烦人又是未来错误的原因,因为很容易忘记$_pages需要超级特殊处理.

对于一个真正的修复,我建议查看$_pages中对象后面的任何类,看看是否可以更改该类.而不是将$_pages作为Iterator,更改$_pages,以便通过IteratorAggregate接口提供迭代器.

这样每个foreach循环都会请求一个单独的迭代器对象并维护单独的状态.

这是一个示例脚本来说明问题,部分来自PHP参考页面:

<?php
class MyIterator implements Iterator
{
    private $var = array();
    public function __construct($array)
    {
        if (is_array($array)) {
            $this->var = $array;
        }
    }
    public function rewind()
    {
        reset($this->var);
    }

    public function current()
    {
        $var = current($this->var);
        return $var;
    }

    public function key() 
    {
        $var = key($this->var);
        return $var;
    }

    public function next() 
    {
        $var = next($this->var);
        return $var;
    }
    public function valid()
    {
        $key = key($this->var);
        $var = ($key !== NULL && $key !== FALSE);
        return $var;
    }
}

// END BOILERPLATE DEFINITION OF ITERATOR, START OF INTERESTING PART

function getMyArrayThingy(){
    /* 
     * Hey, let's conveniently give them an object that
     * behaves like an array. It'll be convenient! 
     * Nothing could possibly go wrong, right?
     */
    return new MyIterator(array("a","b","c"));  
}


// $arr = array("a,b,c"); // This is old code. It worked fine. Now we'll use the new convenient thing!
$arr = getMyArrayThingy();

// We expect this code to output nine lines, showing all combinations of a,b,c 
foreach($arr as $item){
        foreach($arr as $item2){
                echo("$item, $item2\n");
        }
}
/* 
 * Oh no! It printed only a,a and a,b and a,c! 
 * The outer loop exited too early because the counter
 * was set to C from the inner loop.
 */

标签:php,scope,pointers,zend-framework,zend-view
来源: https://codeday.me/bug/20190630/1338227.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有