1.基本介绍
oop的三大特征:封装、继承、多态
封装就是把抽象出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只能通过被授权才能对数据进行操作。
1.1 封装的具体实现-访问修饰符
访问修饰符包括public、protected、private,分别是公开的、受保护的、私有的,访问修饰符对常用属性和成员方法都适用
优先级:public>protected>private
- public :在类的内部、外部、子类都可以访问
- protected:只能在本类和子类中使用
- private:只能在本类中使用
案例说明:
<?php //访问修饰符案例 class Person{ public $name; protected $age; private $sex; public function __construct($name,$age,$sex){ $this->name = $name; $this->age = $age; $this->sex = $sex; } //三种不同的访问修饰符 public function getName(){ echo '<br> name = '.$this->name; } protected function getAge(){ echo '<br> age = '.$this->age; } private function getSex(){ echo '<br> sex = '.$this->sex; } public function show(){ echo '<br> 属性age = '. $this->age; echo '<br> 属性sex = '. $this->sex; echo $this->getAge(); echo $this->getSex(); } } $p1=new Person('张三',23 ,'男'); //public修饰的属性和方法可以在任何地方使用 echo'<br> name = '. $p1->name; echo '<br>'. $p1->getName(); //不能被调用,受保护的方法不能在类的外部使用 //echo '<br> age = '. $p1->age; //echo '<br> sex = '. $p1->sex; //不能被调用,私有的的方法不能在类的外部使用 //echo '<br> age = '. $p1->getAge(); //echo '<br> sex = '. $p1->getSex(); //要想调用 在本类中定义一个public的方法,把protected和private修饰的属性和方法在一个公开的方法中调用 echo $p1->show(); ?>
1.2 如何访问protected和private属性的三种形式
- 使用魔术方法__get和__set来实现对protected和private属性的操作
<?php //访问修饰符案例 class Person{ public $name; protected $age; private $sex; public function __construct($name,$age,$sex){ $this->name = $name; $this->age = $age; $this->sex = $sex; } //使用__set方法修改属性 public function __set($pro_name,$pro_val){ //判断当前对象是否存在传入的变量 if(property_exists($this,$pro_name)){ $this->$pro_name = $pro_val; }else{ echo '<br>当前属性名不存在!!!'; } } //使用__get方法获取属性 public function __get($pro_name){ if(property_exists($pro_name)){ return $this->$pro_name; }else{ echo '<br>当前属性名不存在!!!'; } } } $p1=new Person('张三',23 ,'男'); //修改被protected和private修饰的属性 echo '<br>' .$p1->age=24; echo '<br>' .$p1->sex='女'; ?>
优缺点:
- 优点:简单,一对__set和__get就可以搞定所有的private和protected修饰的属性
- 缺点:不够灵活,没有办法对各个属性进行控制和验证
- 对每个private和protected属性都提供一对get和set方法,这个就可以对每个属性进行单独的验证和控制
<?php //访问修饰符案例 class Person{ public $name; protected $age; private $sex; public function __construct($name,$age,$sex){ $this->name = $name; $this->age = $age; $this->sex = $sex; } //使用setXxx方法验证修改age属性 public function setAge($age){ //判断传入的值是不是数字且要大于0 if(is_numeric($age) && $age > 0 ){ $this->age= $age; }else{ echo '<br>当前属性值格式不正确!!!'; } } //使用getXxx方法获取age属性 public function getAge(){ return $this->age; } //使用setXxx方法验证修改sex属性 public function setSex($sex){ //判断传入的值是不是数字且要大于0 if($sex=='男'|| $sex == '女' ){ $this->sex= $sex; }else{ echo '<br>当前属性值格式不正确!!!'; } } //使用getXxx方法获取sex属性 public function getSex(){ return $this->sex; } } $p1=new Person('张三',23 ,'男'); //修改被protected和private修饰的属性 $p1->setAge(24); echo '<br>' .$p1->getAge(); $p1->setSex('女'); echo '<br>' .$p1->getSex(); ?>
优缺点:
- 优点:可以对每个属性进行验证,很灵活
- 缺点:会造成比较多的setXxx和getXxx方法,但这个也没什么大的问题
- 推荐使用这样的方法
- 写一个成员方法,可以根据业务逻辑,一次性对多个属性批量操作
<?php //访问修饰符案例 class Person{ public $name; protected $age; private $sex; public function __construct($name,$age,$sex){ $this->name = $name; $this->age = $age; $this->sex = $sex; } //使用setXxx方法验证修改age属性 public function setAge($age){ //判断传入的值是不是数字且要大于0 if(is_numeric($age) && $age > 0 ){ $this->age= $age; }else{ echo '<br>当前属性值格式不正确!!!'; } } //使用getXxx方法获取age属性 public function getAge(){ return $this->age; } //使用setXxx方法验证修改sex属性 public function setSex($sex){ //判断传入的值是不是数字且要大于0 if($sex=='男'|| $sex == '女' ){ $this->sex= $sex; }else{ echo '<br>当前属性值格式不正确!!!'; } } //使用getXxx方法获取sex属性 public function getSex(){ return $this->sex; } //创建一个成员方法,获取修改信息 public function undate($age,$sex){ $this->setAge($age); $this->setSex($sex); } //创建一个展示用户信息的方法 public function show(){ echo '年龄是 ' .$this->age; echo '性别是 ' .$this->sex; } } $p1=new Person('张三',23 ,'男'); //修改被protected和private修饰的属性 $p1->undate(24,'女'); $p1->show(); ?>
1.3 在开发中如何选择操作方式
- 如果我们希望直接通过$对象名->属性名的方式来操作属性,则使用__get和__set函数即可
- 如果我们希望使用各个属性分别进行验证则使用setXxx和getXxx
- 如果我们希望同时操作多个属性则选择第三种
1.4 封装的细节说明
- 普通属性要定义为public 、protected和private之一,如果var定义,则被视为公有,静态属性可以不指定访问修饰符,默认为public
- 类中的方法可以被定义为公有、私有、受保护的,如果没有定义默认是public
1.5 对象运算符连用
案例:通过一个学生对象,可以访问到该学生所在班级的信息.
<?php //通过一个学生对象,可以访问到该学生所在班级的信息. //定义一个学生类 class Student{ public $name; private $school; public function __construct($name,$school){ $this->name = $name; $this->school = $school; } public function getSchool(){ return $this->school; } public function setSchool($school){ $this->school=$school; } } //定义一个学校类 class School{ public $name; public $address; private $my_class; public function __construct($name,$address,$my_class){ $this->name = $name; $this->address = $address; $this->my_class = $my_class; } public function getMyClass(){ return $this->my_class; } public function setMyClass($my_class){ $this->my_class=$my_class; } } //定义一个班级类 class Myclass{ protected $name; protected $stu_num; private $introduce; public function __construct($name,$stu_num,$introduce){ $this->name = $name; $this->stu_num = $stu_num; $this->introduce = $introduce; } public function getIntroduce(){ return $this->introduce; } public function setIntroduce($introduce){ $this->introduce=$introduce; } } //首先创建班级对象 $myClass = new Myclass('1107' , 2, '学习的班级'); //创建学校对象 $school = new School('我的学校' , '陕西',$myClass); //创建学生对象 $student = new Student('张三', $school); var_dump($student->getSchool()->getMyClass()->getIntroduce()); ?>
1234