php 为什么能 foreache 到一个对象的受保护属性 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
leeyuzhe
V2EX    PHP

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

  •  
  •   leeyuzhe 2015-08-31 17:03:51 +08:00 3834 次点击
    这是一个创建于 3725 天前的主题,其中的信息可能已经有所发展或是发生改变。
    object (xxx ){ protected '_data' => array (size=6 ){ 0 => 1 => 2 => 3 => 4 => 5 => } } 

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

    14 条回复    2015-08-31 19:28:51 +08:00
    timsims
        1
    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
        2
    haiyang416  
       2015-08-31 17:23:42 +08:00
    如果你在类方法里 foreach 这个数组,当然可以。
    如果是将该对象作为 foreach 的遍历参数,那是因为这个对象实现了 iterator 接口。
    leeyuzhe
        3
    leeyuzhe  
    OP
       2015-08-31 17:28:21 +08:00
    @timsims 我这里真能,我快疯了,不知道为啥。整个对象没有方法只有这么一个 protected 属性。
    你直接 foreach $object 别 foreach ($object->_data )试试
    leeyuzhe
        4
    leeyuzhe  
    OP
       2015-08-31 17:29:41 +08:00
    @haiyang416 对我就是是将该对象作为 foreach 的遍历参数。 iterator 接口如何实现的?整个对象就这么一个属性,没有任何方法,
    jswh
        5
    jswh  
       2015-08-31 17:36:52 +08:00
    父类实现了 iterator 接口?
    haiyang416
        6
    haiyang416  
       2015-08-31 17:39:13 +08:00
    @leeyuzhe 你直接看对象的代码不就知道了,对象从哪来的你应该知道吧。
    http://php.net/manual/en/language.oop5.iterations.php
    freefcw
        7
    freefcw  
       2015-08-31 17:39:13 +08:00
    麻烦请把上下文代码打出来,以及相关的 php 版本等,如此丢出一个问题实在是不负责任的调戏大家
    lijinma
        8
    lijinma  
       2015-08-31 17:41:12 +08:00
    代码贴出来,赶紧的,这像话吗?
    solu
        9
    solu  
       2015-08-31 17:44:00 +08:00
    leeyuzhe
        10
    leeyuzhe  
    OP
       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
        11
    haiyang416  
       2015-08-31 17:56:03 +08:00
    @leeyuzhe 文档上不是写了么, APP_Db_Table_Rowset_Abstract ,你去看它的代码。
    realpg
        12
    realpg  
    PRO
       2015-08-31 18:07:46 +08:00
    原文:

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


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

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

    图一 代码:


    图二 执行:



    ---------------
    综上,明显你这个类不是你自己建的,逐级检查你自己的类的的基类去吧,肯定能找到哪个里面定义了迭代
    invite
        13
    invite  
       2015-08-31 19:21:55 +08:00
    高级的版本, 没用到过.
    timsims
        14
    timsims  
       2015-08-31 19:28:51 +08:00
    APP_Db_Table_Rowset_Abstract.. 这名字好像 ZF1 的 Zend_Db_Table_Rowset_Abstract
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3992 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 05:24 PVG 13:24 LAX 21:24 JFK 00:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86