yii2属性的引入+属性与成员变量3区别3联系+实现属性3步走+提高效率的小技巧

一、属性的引入

举个例子,我们需要对$user对象的public类变量name做trim操作,那么我们首先想到这么做:
$user = new User();
$user->name = trim($name);
然而,这样做有个问题,就是如果我们需要对所有地方的User实例的name属性都要进行trim操作,我们就需要改动多处;另外,假如哪一天我不仅要trim操作,还要首字母大写,那我还得改动很多地方。万一我遗漏了怎么办?
如果我们像这样去定义“属性”,而不是简单粗暴的定义一个名为publice $name的成员变量,那么就可以实现在任何地方,对User的实例的name属性进行trim操作,不用担心有漏网之鱼。同样,有了setter函数,我们如果还可以方便的再加上“首字母大写”的操作:
private $name;
public function setName($value)  
{
    $this->name = ucfirst(trim($value));
}
同样,在属性读之后的自定义处理:
public function getName() 
{
    return ucfirst($this->name); 
}

或者结合更多成员变量做更为复杂的处理:
public function getName() 
{
    return ucfirst($this->firstname).' '.ucfirst($this->lastname); 
}

二、属性与成员变量区别联系

===3个区别
内-外
成员变量是就类的结构而言的概念,属于内的概念。而属性是就类的功能逻辑而言的概念,属于外的概念。

读写权限控制
成员变量没有读写权限控制,而属性可以指定为只读或只写,或可读可写,这就有了权限这么一说

预处理-后处理 
成员变量不对读出作任何后处理,不对写入作任何预处理,而属性则可以

===3个联系
二者的访问形式完全一样。只不过属性访问实际上是getter和setter方法创建了一个名为name的属性。在这个例子里,它指向了一个私有成员变量$name。getter和setter定义的属性和类的成员变量一样。二者的的主要区别在于:当这种属性被读取时,对应的 getter 方法将被调用; 而当属性被赋值时,对应的 setter 方法就调用。如:
pivate $name;//尽管$name是私有,但是调用$name或给$name赋值实际上是分别调用getName()、setName()
$name = $user->name;//等效于$name = $user->getName();
$user->name = 'Jason';//等效于$user = $user->setName('Jason');

 
public成员变量可以视为一个可读可写、没有任何预处理或后处理的属性。而private成员变量由于外部不可见,与属性“外”的特性不相符,所以不能视为属性。同样的,protect属性也不能视为属性

大多数情况下,属性要由成员变量来实现,如:User类有一个成员变量int $age表示年龄。年龄是属性,$age是成员变量

但是二者并没有必然的关系。与非门里就是有2个成员变量($_key1与$_key2),但是有3个属性(key1,key2,output)

class NotAndGate extends Object{
    private $_key1;
    private $_key2;

    public function setKey1($value){
        $this->_key1 = $value;
    }

    public function setKey2($value){
        $this->_key2 = $value;
    }

    public function getOutput(){
        if (!$this->_key1 || !$this->_key2)
            return true;
        else if ($this->_key1 && $this->_key2)
            return false;
    }
}

三、实现属性3步走

class User extends yii\base\Object    // 第一步:继承自 yii\base\Object
{
    private $_title;                 // 第二步:声明一个私有成员变量

    public function getTitle()       // 第三步:提供getter和setter
    {
        return $this->_title;
    }

    public function setTitle($value)
    {
        $this->_title = trim($value);
    }
}
//在读取和写入对象的一个不存在的成员变量时, __get() __set() 会被自动调用。 
public function __get($name)              // 这里$name是属性名
{
    $getter = 'get' . $name;              // getter函数的函数名
    if (method_exists($this, $getter)) {
        return $this->$getter();          // 调用了getter函数
    } elseif (method_exists($this, 'set' . $name)) {
        throw new InvalidCallException('Getting write-only property: '
            . get_class($this) . '::' . $name);
    } else {
        throw new UnknownPropertyException('Getting unknown property: '
            . get_class($this) . '::' . $name);
    }
}
// $name是属性名,$value是拟写入的属性值
public function __set($name, $value)
{
    $setter = 'set' . $name;             // setter函数的函数名
    if (method_exists($this, $setter)) {
        $this->$setter($value);          // 调用setter函数
    } elseif (method_exists($this, 'get' . $name)) {
        throw new InvalidCallException('Setting read-only property: ' .
            get_class($this) . '::' . $name);
    } else {
        throw new UnknownPropertyException('Setting unknown property: '
            . get_class($this) . '::' . $name);
    }
}

这里的访问不存在的成员变量我一直困惑,倒饬了好久。明明是存在啊,存在一个私有的成员变量啊。这个不存在不是真的不存在,而是外部没有权限访问到的意思。

关于public(都可访问)、protected(本类和子类)、private(本类)举例说明如下:

//父类
class father{
 public function a(){
  echo "function a<hr>"; 
 }
 protected function b(){
  echo "function b<hr>"; 
 }
 private function c(){
  echo "function c<hr>"; 
 }
}
//子类
class child extends father{
  function d(){ 
    parent::a();//调用父类的a方法
  }
  function e(){ 
    parent::b(); //调用父类的c方法
  } 
 function f(){ 
    parent::c(); //调用父类的b方法
  } 

}
$father=new father();
$father->a();
$father->b(); //显示错误 外部无法调用私有的方法 Call to protected method father::b() 
$father->c(); //显示错误 外部无法调用受保护的方法Call to private method father::c() 

$chlid=new child();
$chlid->d();
$chlid->e();
$chlid->f();//显示错误 无法调用父类private的方法 Call to private method father::c()

$user = new User();

$user->_title  <==> $user->getTitle()
$user->_title = 'haha'  <==> $user->setTitle('haha')

$_title是私有的,只有类内部能使用(User::_title)。这里的类实例$user是类的实例,$user->_title这是从外部访问的,所以肯定访问不到。所以启动__get()和)__set()继而调用getTitle()和setTitle()来访问。

问:将 private $_title 写成 public $title ,也是可以实现对 $post->title 的读写的。但这不是好的习惯。原因如下:
1、失去了类的封装性。 一般而言,成员变量对外不可见是比较好的编程习惯。 从这里你也许没看出来,但是假如有一天,你不想让用户修改标题了,只要把setter删掉。 怎么确保代码中没有直接修改标题?使用 public $title 的方法的话,那么一旦有没清理干净的对标题的写入,就会抛出异常。而private $title是禁止直接读和取的,可以排查写入的异常
2、牵一发动全身。对于标题的写入,你想去掉空格。 使用setter的方法,只需要像上面的代码段一样在这个地方调用 trim() 就可以了。 但如果使用 public $title 的方法,那么每个写入语句都要调用 trim() 。你能保证没有一处遗漏?private $title只要改一次就能作用所有地方吗????我理解的是public $tittle所有地方都可以调用修改,因而需要所有调用修改的地方都发生变化。但是private $title只有类内部($this->_title)调用修改,只要改这一处就可以了。

四、提高效率的小技巧

使用 $pro = $object->getPro() 来代替 $pro = $object->pro , 用 $objcect->setPro($value) 来代替 $object->pro = $value 。 这在功能上是完全一样的效果,但是避免了使用 __get() 和 __set() ,相当于绕过了遍历的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值