触发__get和__set上的函数的问题

时间:2017-10-27 16:00:32

标签: php

更新

我已经找到了基于duskwuff的答案的解决方案。他确实回答了我问的问题。这是为了未来的任何人 - 主要是我自己。

正如他在$this->{$key} = $val;

中提到的那样

我已更新__constructor以将值分配给受保护的属性$attributes,而不是允许__get__set正确触发的对象本身。

我已将其余代码保持不变。

我最近开始研究一个我不熟悉的新项目,所以请耐心等待。我们编写了自定义类来从MongoDB和Sql Server中获取记录。所有Sql Server和Mongo模型最终将扩展Model类,其中包含各自的MongoModelMsSqlModel类。

Ex:Vendor extends MongoModel> MongoModel extends DatabaseModel> DatabaseModel extends Model

class Model implements JsonSerializable, IteratorAggregate {
   ...
   public function __construct($attributes = []) {
       foreach ( $attributes as $key => $val )
           $this->{$key} = $val;
   }
   ...
   public function &__get($key) {
       if ( $this->isPrivateKey($key) ) {
          return $this->$key;
       } else {
          return $this->attributes[$key];
       }
   }

   public function __set($key, $value) {
       if ( $this->isPrivateKey($key) ) {
           $this->$key = $value;
       } else {
           $this->attributes[$key] = $value;
       }
   }
   ...
}

出于测试目的,我在Cryptarch模型文件中包含了Encryptable类和Vendor类。 Cryptarch只有两个函数encryptdecrypt - 如果需要,我可以发布它们,但它们并不特别,因为我不是安全专家。

trait Encryptable {

    public function &__get($key) {

        $value = parent::__get($key);

        if ( in_array($key, $this->encryptable) ) {
            return Cryptarch::decrypt($value);
        }

        return $value;

    }

    public function __set($key, $value) {

        if ( in_array($key, $this->encryptable) ) {
            $value = Cryptarch::encrypt($value);
        }

        parent::__set($key, $value);

    }

}

class Vendor extends MongoModel
{
    use Encryptable;

    protected $encryptable = [
        'ssn'
    ];
    ...
}

有了这个,我试图在设置(加密)或获取(解密)模型的属性时自动加密/解密敏感信息。

在我的页面上,我只是加载我要测试的记录: $res = Vendor::load('myid'); 如果我var_dump($res->ssn),我会获得加密值,而不是解密值。

如果我设置值$res->ssn = 'somethingelse';var_dump($res->ssn),则输出string(13) "somethingelse"

但是,如果我从__set删除Encryptable功能并尝试输出$res->ssn,我会获得正确解密的值。

如果我var_dump Cryptarch::decrypt($val)中的参数我从数据库中获取了正确的值(已加密) - 但如果我尝试var_dump解密了'来自decrypt函数的结果和exit;返回加密值bool(false),而openssl_decrypt如果失败则应返回$val = 'encryptedstring';。如果我用DB中的直接值覆盖(var_dump)解密用的参数,并且Vendor解密后的结果可以正常工作。

现在,页面/网站的其余部分使用Encryptable特征与bool(false)一起使用。我仍然可以设置值并保存它们并获取它们等。导致挂起的唯一原因是尝试解密该值返回相同的值而不是像openssl_decrypt那样cl1=np.count_nonzero(im == 1) #1=class 1, cl2=np.count_nonzero(im == 2) #2=class 2, cl0=65536-(cl1+cl2) sum_=cl0+cl1+cl2 median_=np.median([cl0,cl1,cl2]) print cl0,cl1,cl2 print median_ try: w0=round(median_/(cl0/sum_),4) # EAFP except ZeroDivisionError: w0=0 try: w1=round(median_/(cl1/sum_),4) # EAFP except ZeroDivisionError: w1=0 try: w2=round(median_/(cl2/sum_),4) # EAFP except ZeroDivisionError: w2=0 W=[w0,w1,w2] print W 如果失败了,并设置值不会加密它。

1 个答案:

答案 0 :(得分:2)

您正在遇到PHP的限制 - __get__set魔术函数仅在访问对象上不存在的属性时触发。永远不会要求它们存在属性。

您对__set的实施包括:

$this->$key = $value;

可以设置对象的属性。以这种方式创建的任何属性都将不再调用__get__set方法。