V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
leeyuzhe
V2EX  ›  PHP

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

  •  
  •   leeyuzhe · 2015-08-31 17:03:51 +08:00 · 3385 次点击
    这是一个创建于 3154 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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
    代码贴出来,赶紧的,这像话吗?
    solupro
        9
    solupro  
       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  
       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   ·   我们的愿景   ·   实用小工具   ·   904 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:07 · PVG 06:07 · LAX 15:07 · JFK 18:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.