学习要点:
1、 OOP的封装
2、 OOP的继承
3、 OOP的多态
面向对象的三个主要特性是封装、继承和多态。
一、OOP的封装
隐藏对象的字段和实现细节,仅对外公开接口,控制在程序中字段的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成 一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
字段的作用域 1.public 公共的 (类外可以访问) 2.private 私有的 (类内可以访问) 3.protected 受保护的 (类内和子类可以访问,类外不可访问) 其实也是私有的,权限不一样而已
创建使用了私有的字段,这样外部就无法访问了
1、类内和类外的概念
【参看demo1.php】
<meta charset="utf-8">
<?php
//创建一个电脑类
class Computer{
//什么叫做类内,就是创建类的两个花括号内的范围叫做类内,其他地方则叫做类外;
//public是字段的公有化,这个字段类外即可访问,赋值和取值;
public $_name;
}
$computer = new Computer(); //这就是类外;
$computer->_name = 'dell';
echo $computer->_name;
?>
2、类外无法访问类内私有字段
【参看demo2.php】
<?php
class Computer{ //大括号里面是类内;
//private是私有化,即对字段进行封装的操作,类外无法访问,取值和赋值都不能操作;
private $_name = '联想';
}
$computer = new Computer();
echo $computer->_name;
?>
3、类外如何访问类内私有字段——通过类内公有方法
【参看demo3.php】
<meta charset="utf-8">
<?php
class Computer{
private $_name = '联想';
//这个时候我采用一个公共对外的方法来访问私有字段
//因为私有字段只能在类内访问,而对外的公共方法是类内的。
//而且公共方式又是公共的,所以类外又可以访问。
public function _run(){
//字段在类内调用的时候必须是类->字段,而$_name只是普通变量而已
//字段在类外调用的方法是对象->字段,而类内就必须使用Computer->_name
//但是在本类中可以用一个关键字来代替Computer,那就是$this
echo $this->_name;
}
}
$computer = new Computer();
$computer->_run();
?>
4、类外对类内赋值和取值——通过设置公有赋值方法和公有取值方法
【参看demo4.php】
<meta charset="utf-8">
<?php
class Computer{
private $_name;
private $_model;
private $_cpu;
private $_keyboard;
private $_show;
private $_zb;
//必须写一个对内的入口,对私有字段进行赋值
public function setName($_name){ //public换成private就会报错
//通常约定俗成,字段是什么名字,你就取什么名字;
//这里的$_name只是一个变量而已,参数而已;
//$this->_name才是类的字段;
$this->_name = $_name;
}
//必须写个对外的入口,才可以取到;
public function getName(){
return $this->_name;
}
}
$computer = new Computer();
$computer->setName('dell');
echo $computer->getName();
?>
5、设置拦截器__set()和__get()实现类外对类内不同字段的赋值和取值
扩展思考:如果类中有很多个字段需要赋值和取值,是不是需要有很多方法来对其进行赋
值和取值呢?答案当然不是;PHP内置两个拦截器(两个方法)专门用于取值和赋值;
__set()和__get();(注意:是两个下划线)
【参看demo5.php】
<meta charset="utf-8">
<?php
class Computer{
private $_name;
private $_model;
private $_cpu;
//采用拦截器进行赋值和取值
//当类外的对象直接调用私有字段时,会跟着检查是否有拦截器;如果没有拦截器直接报错;如果有拦截器就直接拦截下来;
//如果直接对$_name进行赋值,那么__set()方法就会拦截住,就不会报错了;
//赋值
public function __set($_key,$_value){//$_key属性名,$_value属性值;
//那么$_key = '_name' ,那么 $_value = '联想'
//$this->_name = '联想'
//那么$_key = '_cpu', 那么$_value = '四核'
//$this->_cpu = '四核'
//那么$_key = '_model', 那么$_value = 'i7'
//$this->_model = 'i7'
$this->$_key = $_value;
}
//取值方法1:
/*
public function getName(){
echo $this->_name;
echo $this->_model;
echo $this->_cpu;
}
*/
public function __get($_key){
return $this->$_key;
//如果$_key = '_name',那么$this->_name
//如果$_key = '_model',那么$this->_model
//如果$_key = '_cpu',那么$this->_cpu
}
//有个疑问?如果拦截器是私有private,那会出错吗
//不出错!为什么都是私有的?类外还能访问呢?下节课讲解;
}
$computer = new Computer($_key); // new Computer($_key, $value);也可以如何分析??
$computer->_name = '联想';
$computer->_cpu = '四核';
$computer->_model = 'i7';
echo $computer->_name;
echo $computer->_model;
echo $computer->_cpu;
?>
6、设置拦截器__set()和__get()私有的,类外可以实现对类内字段的赋值和取值吗
【参看demo6.php】
<meta charset="utf-8">
<?php
class Computer{
private $_name;
private $_model;
private $_cpu;
//__set()和__get()方法私有了,还是可以执行,是因为目前程序的指针已经在类内了。而类内可以执行封装的方法;
//类内执行私有方法,不会出现任何错误;
//只需要间接的拦截就可以了。拦截是在类内执行的;
//说白了,__set和__get是PHP内置的方法,具有一定的特殊性;
private function __set($_key, $_value){
$this->$_key = $_value;
}
private function __get($_key){
return $this->$_key;
}
}
$computer = new Computer();
$computer->_name = '联想';
$computer->_model = 'i7';
$computer->_cpu = '四核';
echo $computer->_name;
echo $computer->_model;
echo $computer->_cpu;
?>
7、类中常量设置及访问
【参看demo7.php】
常量不是在堆区或栈区,它是在一个数据区中;
<?php
class Computer{
const NAME = 'DELL';//const 定义常量;
}
//常量的输出方法 类::常量 (两个冒号)
echo Computer::NAME;
$computer = new Computer();
$computer ::NAME;
?>
8、普通类字段和类方法在数值累加情况
静态类成员:有时候,可能需要创建供所有类实例共享的字段和方法,这些字段和方法与所有的类实例有关,但不能由任何特定对象调用;
静态类字段、静态类方法;
【参看demo8.php】
<?php
class Computer{
public $_count = 0;
public function _add(){
$this->_count++; //$count = $count +1 $count++
}
}
//做一个累计的效果
$computer1 = new Computer();
$computer1->_add();
echo $computer1->_count;
$computer1->_add();
echo $computer1->_count;
$computer1->_add();
echo $computer1->_count;
echo "<br/>";
$computer2 = new Computer();
$computer2->_add();
echo $computer2->_count;
$computer2->_add();
echo $computer2->_count;
$computer2->_add();
echo $computer2->_count;
?>
9、静态类字段访问方法
上面$_count代码如果设置成静态字段会如何?
静态字段是在一个特定的区域——数据区;静态区只有一个,它是共享的!!!
【参看demo9.php】
<?php
class Computer{
public static $_count=0;
public function _add(){
//如果是静态成员字段,那么就应该用self调用,而不是$this
self::$_count++; //注意:slef调用时候需要有$符号;$this调用的时候不需要有$符号
//普通方法必须实例化才能调用;
}
}
//echo Computer::$_count;
$computer1 = new Computer();
$computer1->_add();
$computer1->_add();
$computer1->_add();
echo Computer::$_count;
echo "<br/>";
$computer2 = new Computer();
$computer2->_add();
$computer2->_add();
$computer2->_add();
echo Computer::$_count;
?>
10、静态类字段和静态类方法的访问方法
【参看demo10.php】
<?php
class Computer{
public static $_count = 0;
public static function _run(){
self::$_count++;
}
}
//普通方法需要实例化才能使用;
//而静态方法不需要实例化直接能使用,不需要new;参看内存说明图;
Computer::_run();
Computer::_run();
Computer::_run();
Computer::_run();
echo Computer::$_count;
?>
11、instanceof关键字使用方法
instanceof关键字:可以确定一个对象是类的实例、类的子类还是实现了某个特定的接口,并进行相应的操作;
【参看demo11.php】
<?php
class Computer{
}
$computer = new Computer();
//左边写上对象的名字,右边写上类的名字
echo ($computer instanceof Computer);
//返回值是1表示真,1表示假;
?>