面向对象三大特性:封装、继承、多态。
OOP封装
隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
成员字段的作用域:
1、public 公共的(类外可以访问)
2、private 私有的(类内可以访问)
3、protected 受保护的(类内和子类可以访问,类外不可以访问)
创建私有字段,类外就无法访问了:
<?php
class Computer{
private $_name='联想';
}
?>
通过一个公共方法作为入口,访问私有成员字段,必须使用$this关键字。
<?php
class Computer{
private $_name='联想';
//采用一个公共对外的方法来访问私有字段
//因为私有字段只能类内访问,而对外的公共方法是类内的。
//而且公共方法又是公共的,所以类外又可访问。
public function _run(){
//成员字段在类内调用的时候必须是:类->字段,而$_name只是一个普通变量而已。
//成员字段在类外调用的方法是:对象->字段,但类内就必须使用Computer->_name
//在本类中,可以用$this来代替Computer。
echo $this->_name;
}
}
$computer = new Computer();
$computer->_run();
?>
以上原理是:通过在类内创建公共方法,用来访问私有字段。然后在类外就可以调用该公共方法,从而达到访问私有字段的目的。
在类外对私有字段进行赋值和取值:
取值:
<?php
class Computer{
private $_name='联想';
//对外的入口方法
public function getName(){
echo $this->_name;
}
}
$computer = new Computer();
$computer->getName();
?>
赋值并取值:
<?php
class Computer{
private $_name;
//需要写一个对内的入口,对私有字段进行赋值
public function setName($_name){
//指向私有字段$_name,并将参数$_name(变量)的值赋给_name。
//$this->_name是类的字段。
$this->_name=$_name;
}
//对外的入口方法,访问私有字段$_name,也就是对私有字段取值。
public function getName(){
echo $this->_name;
}
}
$computer = new Computer();
//赋值
$computer->setName('dell');
//取值
$computer->getName();
?>
多个字段情况下的赋值和取值
在这里,PHP内置了两个方法(拦截器)用于赋值和取值:__set()
,__get()
。
<?php
class Computer{
private $_name;
private $_cpu;
private $_keybord;
//使用拦截器进行赋值和取值
//赋值,需要注意:__set()必须传两个值(变量),比如:$_key,$_value,可以随意命名
public function __set($_key,$_value){
//实际上$_key ='_name',$_value='联想'
//相当于$this->_name='联想';
$this->$_key=$_value;
}
//取值,__get()必须传一个值
public function __get($_value){
//返回相应的值
return $this->$_value;
}
}
//实例化对象
$computer = new Computer();
//赋值
$computer->_name='联想';
$computer->_cpu='i7';
$computer->_keybord='xx';
//取值
echo $computer->_name;
echo $computer->_cpu;
echo $computer->_keybord;
?>
注意:__set()
和__get()
方法私有了,还可以执行,是因为目前程序的指针已经在类内了,而类内可以执行封装的方法。类内执行私有方法不会出现任何错误。
设置成私有方法是,它只需要间接拦截即可,拦截是在类内进行的
私有化:
<?php
class Computer{
private $_name;
private $_cpu;
private $_keybord;
//使用拦截器进行赋值和取值
//赋值,需要注意:__set()必须传两个值(变量),比如:$_key,$_value,可以随意命名
private function __set($_key,$_value){
//实际上$_key ='_name',$_value='联想'
//相当于$this->_name='联想';
$this->$_key=$_value;
}
//取值,__get()必须传一个值
private function __get($_value){
//返回相应的值
return $this->$_value;
}
}
$computer = new Computer();
//赋值
$computer->_name='联想';
$computer->_cpu='i7';
$computer->_keybord='xx';
//取值
echo $computer->_name;
echo $computer->_cpu;
echo $computer->_keybord;
?>
常量(constant)
在类中可以定义常量,用来表示不会改变的值。对于从该类实例化的任何对象来说,常量值在这些对象的整个生命周期都保持不变。
<?php
class Computer{
//常量名用大写
const NAME ='DELL';
}
//常量输出方法:类::常量
echo Computer::NAME;
?>
静态类成员
有时候,可能需要创建供所有类实例共享的字段和方法,这些字段和方法与所有的类实例有关,但不能yo由任何特定对象调用。
静态字段:
<?php
class Computer{
public static $_count = 0;
public function _add(){
//如果是静态成员,那就应该用self调用,而不是$this
//self调用的时候,是需要$符号的
//::是类中静态方法和静态属性的引用方法
self::$_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;
?>
静态方法:
<?php
class Computer{
public static $_count = 0;
public static function _run(){
self::$_count++;
}
}
Computer::_run();
Computer::_run();
Computer::_run();
echo Computer::$_count;
?>
OOP继承
继承是从一个基类得到一个或多个类的机制。
PHP中,类继承通过extends关键字实现,继承自其它类的类成为子类或派生类,子类所有继承的类成为父类或基类。(PHP只支持单继承,不支持方法重载)。
一个简单的继承案例:
<?php
//父类,电脑类
class Computer{
public $_name ='联想';
public function _run(){
echo '联想在运行';
}
}
//子类,笔记本电脑类,继承自电脑类
class NoteComputer extends Computer{
}
$notecomputer = new NoteComputer();
echo $notecomputer->_name;
$notecomputer->_run();
?>
字段和方法的重写(覆盖)
有时候,并不是特别需要父类的字段和方法,可以通过子类的重写来修改父类的字段和方法。
小例子:
<?php
//父类,电脑类
class Computer{
public $_name ='联想';
public function _run(){
echo '联想在运行';
}
}
//子类,笔记本电脑类,继承自电脑类
class NoteComputer extends Computer{
//若不需要父类的字段和方法,可以重写字段和方法覆盖
public $_name='DELL';
public function _run(){
echo 'DELL在运行';
}
}
$notecomputer = new NoteComputer();
echo $notecomputer->_name;
$notecomputer->_run();
?>
子类调用父类的字段或方法
为了安全,一般将父类的方法封装起来,这样外部就无法调用,只能被继承它的子类所看到。这时,就需要通过子类操作来调用父类。
例子:
<?php
class Computer{
//私有化,但是无法被子类继承,这时候应该用受保护的修饰符来封装
protected $_name ='联想';
protected function _run(){
echo '联想在运行';
}
}
class NoteComputer extends Computer{
public function getTOP(){
echo $this->_name;
}
}
$notecomputer = new NoteComputer();
$notecomputer->getTOP();
?>
通过重写调用父类的方法
有时候需要通过重写的方法里能够调用父类的方法内容,这时就必须使用语法:父类名::方法() 或者 parent::方法() 即可调用。后面的比较新,推荐后一种。
例子:
<?php
class Computer{
public $_name ='联想';
public function _run(){
echo '联想在运行';
}
}
class NoteComputer extends Computer{
public $_name='DELL';
public function _run(){
echo 'DELL在运行';
echo parent::_run();
}
}
$notecomputer = new NoteComputer();
echo $notecomputer->_name;
$notecomputer->_run();
?>
final关键字
可以防止类被继承,有时候只想做个独立的类,不想被其他类继承使用,那就需要用到final。建议只是单独的类都加上这个关键字。
例子:
<?php
//final如果加载类前, 表示该类不能被继承。
// final class Computer{
// }
class Computer{
//final如果加在方法前,表示不能重写此方法
final public function _run(){
}
}
class NoteComputer extends Computer{
public function _run(){
}
}
?>
OOP多态
抽象类和方法(abstract)
抽象方法很特殊,只在父类中声明,但在子类中实现。只有声明abstract的类可以声明抽象方法。
规则:
1、抽象类不能被实例化,只能被继承;
2、抽象方法必须被子类方法重写。
<?php
//抽象类不能被实例化,也就是创建对象。
//只要类里有一个抽象方法,这个类就必须是抽象类。类前必须加上abstract
abstract class Computer{
//抽象类可以有成员字段
public $_name ='联想';
//在抽象类里创建一个抽象方法
//抽象方法不能够实现方法体的内容
abstract public function _run();
//在抽象类里创建一个普通方法
public function _run2(){
echo '我是父类的普通方法';
}
}
//抽象类是用来给子类继承和资源共享的。
class NoteComputer extends Computer{
//抽象类里的抽象方法,子类必须重写,不然会报错。
//抽象类的普通方法不需要重写,子类会直接继承下来
public function _run(){
echo '我是子类的方法';
}
}
$notecomputer =new NoteComputer();
$notecomputer->_run();
$notecomputer->_run2();
//可以调用成员字段
echo $notecomputer->_name;
?>
接口(interface)
接口定义了实现某种服务的一般规范,声明了所需函数和常量,但不指定如何实现,之所以不给出实现的细节,是因为不同的实体可能需要用不同的方式来实现公共的方法定义,关键是要建立必须实现一组一般原则,只要满足了这些原则才能说实现了这个接口。
规则:
1、类全部为抽象方法(不需要声明abstract);
2、接口抽象方法必须是public;
3、成员(字段)必须是常量;
简单接口:
<?php
//接口也不能被实例化
//接口是为了规范实现它的子类,以达到统一目的。
interface Computer{
//成员字段必须是常量
const NAME='联想';
//接口里的所有方法都是抽象方法,不能写方法体
//并且接口的抽象方法不需要写abstract
public function _run();
public function _run2();
}
//子类继承接口的说法,叫实现。
class NoteComputer implements Computer{
public function _run(){
echo '我重写了run';
}
public function _run2(){
echo '我重写了run2';
}
}
$notecomputer = new NoteComputer();
$notecomputer->_run();
$notecomputer->_run2();
//接口::常量
echo Computer::NAME;
?>
多态
多态是指OOP能够根据使用类的上下文来重新定义或改变类的性质或行为,或者说接口的多种不同的实现方式即为多态。把不同的子类对象都当做父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
例子:
<?php
//多态,即多种形态。
//一个动作由不同的人去执行,而产生不同的效果或者这结果,即为多态;
//一个人通过不同的状态去执行同一种动作,形成不同的结果,也称其为多态。
//创建一个接口来规范运行方法
interface Computer{
public function version(); //这个方法表示采用什么电脑
public function work();//这台电脑是怎么运行的。
}
//创建一个笔记本类来实现接口
class NoteComputer implements Computer{
public function version(){
echo '笔记本';
}
public function work(){
echo '便捷式运行win7';
}
}
//创建一个台式机的类来实现接口
class DesktopComputer implements Computer{
public function version(){
echo '台式机';
}
public function work(){
echo '在工作中运行xp';
}
}
//创建一个用户
class Person{
//创建一个方法来接收电脑对象(笔记本电脑,台式电脑)
//至于怎么接收,将他们的对象传进来就行了。
public function _use($type){
echo '这个人的';
$type->version();
$type->work();
}
}
//现有一个接口,两个类。
//创建笔记本对象
$notecomputer = new notecomputer();
//创建台式机对象
$descktopcomputer = new DesktopComputer();
//创建一个人对象
$person =new Person();
//使用笔记本电脑
$person->_use($notecomputer);//这种传递叫 对象引用的传递。
//这个人也可以换成使用台式机
$person->_use($descktopcomputer);
?>
小结:多态的原理,就是类写好了,不去修改,只需要在类外调用参数的更改。而最后结果也会改变。