doude2635 2017-11-28 02:15
浏览 118

如何在PHP中使用重载(使用__get()魔术方法或其他方式)访问类中的现有私有属性?

Consider below working code :

<?php
  class PropertyTest {
    /**  Location for overloaded data.  */
    private $data = array();

    /**  Overloading not used on declared properties.  */
    public $declared = 1;

    /**  Overloading only used on this when accessed outside the class.  */
    private $hidden = 2;

    public function __set($name, $value) {
      echo "Setting '$name' to '$value'
";
      $this->data[$name] = $value;
    }

    public function __get($name) {
      echo "Getting '$name'
";
      if (array_key_exists($name, $this->data)) {
        return $this->data[$name];
      }

      $trace = debug_backtrace();
      var_dump($trace); die;
      trigger_error(
        'Undefined property via __get(): ' . $name .
        ' in ' . $trace[0]['file'] .
        ' on line ' . $trace[0]['line'],
        E_USER_NOTICE);
        return null;
    }

    /**  As of PHP 5.1.0  */
    public function __isset($name) {
      echo "Is '$name' set?
";
      return isset($this->data[$name]);
    }

    /**  As of PHP 5.1.0  */
    public function __unset($name) {
      echo "Unsetting '$name'
";
      unset($this->data[$name]);
    }

    /**  Not a magic method, just here for example.  */
    public function getHidden() {
      return $this->hidden;
    }
  }


  echo "<pre>
";

  $obj = new PropertyTest;

  $obj->a = 1;
  echo $obj->a . "

";

  var_dump(isset($obj->a));
  unset($obj->a);
  var_dump(isset($obj->a));
  echo "
";

  echo $obj->declared . "

";

  echo "Let's experiment with the private property named 'hidden':
";
  echo "Privates are visible inside the class, so __get() not used...
";
  echo $obj->getHidden() . "
";
  echo "Privates not visible outside of class, so __get() is used...
";
  echo $obj->hidden . "
";
?>

Output :

Setting 'a' to '1'
Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'


Notice:  Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29 

I understood everything in the code. I only have a concern in accessing the private property $hidden outside the class using magic method __get()(or some other way but in overloading). I mean by usage of Overloading only.

But currently I'm not able to achieve that. Getting User Notice for the same.

  • 写回答

1条回答 默认 最新

  • drr47973 2017-11-28 02:51
    关注

    I don't understand your problem

     <?php
        class TestClass{
    
            private $private = 'true';
    
            public function __get($key){
                if( isset($this->{$key}) ){
                    return $this->{$key};
                }
                throw new Exception('Undefined object property '.__CLASS__.'::'.$key);
            }
        }
    
    echo (new TestClass())->private;
    

    Outputs

    true
    

    See for yourself here

    There is no reason you can't do that from the class where $private is defined in. That said it's probably a poor design choice.

    Now if you are trying to do this ( Access private parent property from a child )

    <?php
        class TestClass{
            private $private = 'true';
        }
    
        class ChildClass extends TestClass{            
            public function __get($key){
                if( isset($this->{$key}) ){
                    return $this->{$key};
                }
                throw new Exception('Undefined object property '.__CLASS__.'::'.$key);
            }
        }
    
    echo (new ChildClass())->private;
    

    Outputs ( our exception )

    <b>Fatal error</b>:  Uncaught Exception: Undefined object property ChildClass::private in
    

    See it here

    Indeed, and if you want to get real Crazy you can do this:

    <?php
        class TestClass{
            private $private = 'true'; //not visible to child
    
             //called -via- child class
            public function parentEcho(){
                echo "
    Parent: {$this->private}
    ";
                return $this; //return this for chaining
            }
        }
    
        class ChildClass extends TestClass{
            private $private = 'false'; //this is not parent::$private
    
            public function childEcho(){
                echo "
    Child: {$this->private}
    ";
                return $this;
            }
        }
    
    (new ChildClass())->childEcho()->parentEcho();
    

    Outputs

    Child: false
    
    Parent: true
    

    Check this out here

    This illustrates the scope of a private property Is only within this class. Even children know nothing about it. However with a method in parent that accesses is directly ( not overwritten in child ) it can still be reached by inheritance. Because, the child inherits the method and the method is defined within the class ( parent ) which can access it.

    But if you truly want your mind blown (Reflection):

    <?php
        class TestClass{
            private $private = 'true';
    
            public function parentEcho(){
                echo "
    Parent: {$this->private}
    ";
                return $this;
            }
        }
    
    $Obj = new TestClass();
    
    $Obj->parentEcho();
    
    echo "
    ";
    
    $ReflectionObj = new ReflectionObject($Obj);
    
    $ReflectionProperty = $ReflectionObj->getProperty('private');
    $ReflectionProperty->setAccessible(true);
    
    echo $ReflectionProperty->getValue($Obj)."
    ";
    
    $ReflectionProperty->setValue($Obj, 'false' );
    
    echo $ReflectionProperty->getValue($Obj)."
    ";
    
    $Obj->parentEcho();
    

    Outputs

    Parent: true
    
    true
    false
    
    Parent: false
    

    You can see this darling here

    Reflection allows you to inspect the definition of other Objects, methods, function etc... (introspection) from outside of them. I am not to sure with recent versions of PHP, but in the past their was a significant performance hit when using reflection (it wasn't like seconds, more like 10s of milliseconds ). However, there are some really neat things you can do with it.

    http://php.net/manual/en/intro.reflection.php

    That all said, you can access it with a simple get method, and semantically that is probably the best way.

    public method getProperty() {
        return $this->property;
    }
    public method setProperty($property) {
        return $this->property = $property;
    }
    

    A few things I feel I must mention

    • I rarely, rarely, rarely ever use private properties. The problem with private properties is if you decide to extend the class, later, you'll wind up changing most of them over to protected anyway. private - visible only within the scope of this class.

    • I use protected Something like 99% of the time. It just works. protected - visible only within the scope of this class's descendants.

    • I refuse to use public properties as it's a poor design, IMO, that leads to a lot of woes when it comes time to maintain your code. Classes should be Black Boxes, which means the internal workings of them should not be exposed to the rest of your code. The problem with exposing all the workings of you class is you could rename a property without thinking and break some piece of code somewhere. At least with public methods you can rename the properties, re-work the method and nothing outside the class should be affected (as long as the method name, inputs, and outputs don't change) public - visible within the scope of the caller (and class's descendants)

    Cheers, and happy coding.

    评论

报告相同问题?

悬赏问题

  • ¥15 求解 yolo算法问题
  • ¥15 虚拟机打包apk出现错误
  • ¥30 最小化遗憾贪心算法上界
  • ¥15 用visual studi code完成html页面
  • ¥15 聚类分析或者python进行数据分析
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝