php 为什么能 foreache 到一个对象的受保护属性

2015-08-31 17:03:51 +08:00
 leeyuzhe
object (xxx ){
  protected '_data' => 
    array (size=6 ){
      0 => 

      1 => 

      2 => 

      3 => 

      4 => 

      5 => 
     }
}

对象大概就长得这样,里面有一个唯一的受保护属性_data,属性里存着一个数组array。然后我尝试foreach这个数组,神奇的事情发生了,_data里面的array数组被遍历出来了。

3396 次点击
所在节点    PHP
14 条回复
timsims
2015-08-31 17:18:13 +08:00
```
class Object
{
protected $_data = [1,2,3];
}

$object = new Object;
foreach ($object->_data as $v ) {

echo $v;
}

```
然而并不能
FatalErrorException
Cannot access protected property Object::$_data


我猜这个对象是不是实现了 ArrayAccess 接口或者用了魔术方法?
haiyang416
2015-08-31 17:23:42 +08:00
如果你在类方法里 foreach 这个数组,当然可以。
如果是将该对象作为 foreach 的遍历参数,那是因为这个对象实现了 iterator 接口。
leeyuzhe
2015-08-31 17:28:21 +08:00
@timsims 我这里真能,我快疯了,不知道为啥。整个对象没有方法只有这么一个 protected 属性。
你直接 foreach $object 别 foreach ($object->_data )试试
leeyuzhe
2015-08-31 17:29:41 +08:00
@haiyang416 对我就是是将该对象作为 foreach 的遍历参数。 iterator 接口如何实现的?整个对象就这么一个属性,没有任何方法,
jswh
2015-08-31 17:36:52 +08:00
父类实现了 iterator 接口?
haiyang416
2015-08-31 17:39:13 +08:00
@leeyuzhe 你直接看对象的代码不就知道了,对象从哪来的你应该知道吧。
http://php.net/manual/en/language.oop5.iterations.php
freefcw
2015-08-31 17:39:13 +08:00
麻烦请把上下文代码打出来,以及相关的 php 版本等,如此丢出一个问题实在是不负责任的调戏大家
lijinma
2015-08-31 17:41:12 +08:00
代码贴出来,赶紧的,这像话吗?
solupro
2015-08-31 17:44:00 +08:00
leeyuzhe
2015-08-31 17:51:55 +08:00
@haiyang416 @freefcw @lijinma @solupro
首先是返回这个对象的方法。
```
/**
* Fetches all rows.
*
* @param string|array $where OPTIONAL An SQL WHERE clause
* @param string|array $order OPTIONAL An SQL ORDER clause.
* @param int $count OPTIONAL An SQL LIMIT count.
* @param int $offset OPTIONAL An SQL LIMIT offset.
* @return APP_Db_Table_Rowset_Abstract object
*/
public function fetchAll ($where = null, $order = null, $count = null, $offset = null )
{
$table = $this->_schema . '.' . $this->_db->quoteIdentifier ($this->_name );
$select = "SELECT * FROM $table";

// if ($where !== null )
if ($where !== null && !empty ($where ))
{
$select .= ' WHERE ' . $this->_where ($where );
}

if ($order !== null && !empty ($order ))
{
$select .= ' ORDER BY ' . $this->_order ($order );
}


if ($count !== null || $offset !== null )
{
$select = $select . $this->_db->limit ($count, $offset );
// $select = $this->_db->limit ($select, $count, $offset );
}

$data = $this->_fetch ($select );

require_once 'APP/Loader.php';
APP_Loader::loadClass ($this->_rowsetClass );
return new $this->_rowsetClass ($data );
}





```
然后是包含进来的 APP/Loader.php
```
<?php

/**
* @category APP
* @package APP_Loader
* @version $Id: Loader.php v1.0 2009-2-25 0:08:04 tomsui $
*/
class APP_Loader
{
/**
* Load a class
*
* Load a APP class file. If the class already exists in memory, return
* directly.
*
* @static
* @param string $class String name of the class to load.
* @param array $config OPTIONAL; an array with adapter parameters.
* @return void
* @throws APP_Exception
*/
public static function loadClass ($class )
{
if (class_exists ($class, false ) || interface_exists ($class, false )) {
return;
}

$file = str_replace ('_', DIRECTORY_SEPARATOR, $class ) . '.php';
self::_securityCheck ($file );

require ($file ) ;
}

/**
* Autoload switch
*
* if switch opens, APP class can be used without loading previously
*
* @static
* @param boolean $use to set wheather Autoload switcher in use or not.
* @return void
*/
public static function Autoload ($use = true )
{
if ($use ){
spl_autoload_register (array ('APP_Loader', 'loadClass'));
}else{
spl_autoload_unregister (array ('APP_Loader', 'loadClass'));
}

}

/**
* Security Check
*
* File name of APP classs can just contain alpha,digits,backslash (/),
* slash (\),underline (_),period (.) and dash (-). If contains other irregular
* charactor, an APP_Exception is thrown.
*
* @static
* @param boolean $filename the filename string to be check.
* @return void
* @throws APP_Exception
*/
protected static function _securityCheck ($filename )
{
if (preg_match ('/[^a-z0-9\\/\\\\_.-]/i', $filename )) {
require_once 'APP/Exception.php';
throw new APP_Exception ('Security check: Illegal character in filename');
}
}
}


```
haiyang416
2015-08-31 17:56:03 +08:00
@leeyuzhe 文档上不是写了么, APP_Db_Table_Rowset_Abstract ,你去看它的代码。
realpg
2015-08-31 18:07:46 +08:00
原文:

对象大概就长得这样,里面有一个唯一的受保护属性_data ,属性里存着一个数组 array 。然后我尝试 foreach 这个数组,神奇的事情发生了,_data 里面的 array 数组被遍历出来了。


foreach 这个数组还是 foreach 这个类的实例?
你说的 foreach 这个数组,那就是直接对这个类的成员进行 foreach ,见 1 楼 @timsims 的测试

如果遍历的是这个对象,那么测试如下:

图一 代码:


图二 执行:



---------------
综上,明显你这个类不是你自己建的,逐级检查你自己的类的的基类去吧,肯定能找到哪个里面定义了迭代
invite
2015-08-31 19:21:55 +08:00
高级的版本, 没用到过.
timsims
2015-08-31 19:28:51 +08:00
APP_Db_Table_Rowset_Abstract.. 这名字好像 ZF1 的 Zend_Db_Table_Rowset_Abstract

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/217356

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX