楠Go随笔

第十一课:PHP面向对象基础知识

2018-01-31 08:53:43 admin 阅读 网站首页 > PHP > PHP学习

试想一下在面向过程的开发中,伴随着整个工程的壮大,代码块的量也随着增大, 采用函数封装的方式把代码块隐藏起来实现复用。但是函数的个数也开始庞大起来,彼此之间的关系越来越脆弱,以至于没有关系。在整个庞大的工程中需要厘清模块与模块的关系实在是有点力不从心。哪怕项目经理对模块划分成不同文件进行动态导入,也没有能解决模块之间的关系问题。这个时候面向对象设计OOP就可以发挥出应有的作用了。

在面向对象设计中,我们会听到 ,并且知道 对象是类的实例。打成比方的话,类 好比就是一张建筑蓝图 ,对象就是在这一张蓝图下根据不同的规格(属性)所建造成(行为)的一所所房子。

以 人类 作为 类 进行分析,人类应该具有 身高、肤色、性别、年龄等属性,以及跑、叫等行为。这些属性和行为都是跟人类紧密联系相关联起来的,也就是说两者之间关系很紧密,对里面的行为和属性进行润色和修饰并不影响其他事物类。

面向对象编程(OOP)是一种计算机编程架构,OOP能实现软件工程的三个目标:重用性、灵活性和拓展性。

面向对象编程的三大特性是:继承、封装和多态。

在讲解面向对象编程之前,我们需要掌握几个概念。

类的定义 类是具有相同特性的对象的集合,集合里面的属性、行为密切关联。

实例化 对类进行解析,实例出的一个变量,该变量是一种对象。

抽象类 抽象类是对类的一种概括抽象,勾勒出该类所具有的行为。如果说建筑蓝图是类,那么抽象类就是针对建筑说需要的一系列规范(不需要指明具体实现,但必须有相应的操作)。

基类 被子类所继承的类就叫基类,也叫父类。因为有了继承,所以无须重复实现原有的功能,可以在基类的基础上进一步完善设置,降低整个工作量,

子类 继承父类的实现类就叫子类,它是对父类的进一步完善或补充。例如父类是某小区建筑蓝图,子类就可以是其他小区建筑蓝图,可能在外观和材料上有所区别,但是打地基、判断建筑物是否垂直的方法总是相同的吧。

最终类 有些情况下,一些类不允许被继承,好比如第三方的API接口类,已经是官方完善过的,请求接口的行为不能被修改。(你去修改第三方请求接口的URL对你有什么用呢?)类似这种情况下不允许继承。

属性 类里面有行为和属性,属性就是类的一些参数字段,比如 人 这个类 有年龄、性别、身高、肤色等属性。

行为 行为有关键字 function 定义,在面向过程的开发中,我们称其为函数,但是在面向对象开发中,我们将其称为行为,行为是一种方法,该方法与其类紧密相关。

构造方法  定义好类之后,需要进行实例化为对象,在实例化时PHP环境会调用类的一个特殊的方法进行初始化操作,这个方法叫构造方法,在PHP5.0以前构造函数方法名与类名相同,PHP5.0开始为了解耦,指定构造方法名同一为 __construct 前面是两条下划线,为了兼容PHP4.0的构造函数,以上两种方式并存。需要注意的是如果没有定义构造函数,系统会自动创建一个构造函数做初始化,也不能定义多个不同参数的构造函数,在实例化时去选择指定的构造函数。因为PHP没有重载这个概念。

析构方法 与构造方法相反,析构方法是在对象释放之前做收尾的工作,PHP5.0才有析构方法。析构方法的名称为 __destruct

类关键字 

关键字作用
class声明一个类的关键字
abstract修饰一个类或行为 表示这是一个抽象类或一个抽象方法,被该关键字所修饰的类将不能被实例化,需要被子类实现才能实例化。
new实例化一个类的关键字 生成一个对象
static被该关键字所修饰的类、方法、属性是静态的,不需要实例化,被所有对象所共享
final被该关键字修饰的类或方法表示不能被继承、不能被重写,不能用来修饰属性。
this表示在在对象内部指向当前对象的一个指针,用于在内部调用其他属性或方法
parent表示在子类对象中指向其父类对象的一个指针,用于在内部调用父类的一些方法或属性
self指向类自身,用于静态方法或静态类,获取共享资源,不能指向任何实例化过的对象
const定义类级别常量 可以被类的所有对象所共享 不能修改其值
extends继承父类的关键字 PHP只支持单继承,不允许同时继承多个父类
implements继承接口关键字 支持多接口继承 接口里面的方法都为抽象方法 需要继承类去实现
interface定义接口关键字,里面只能包括抽象方法和常量
namespace命名空间关键字,PHP5.3新增,设置一个逻辑目录划分,解决类名冲突,在定义命名空间之前不能有任何输出
use引入类名全称,包括命名空间


魔术方法 跟构造方法一样都以双下划线__开头

方法描述
__set($key,$value)按预定义的方式 设置类中私有属性的值,系统根据需要自动调用
__get($key)按预定义的方式 获取类中私有属性的值,系统根据需要自动调用
__iset($key)当类外部调用isset()去判断私有成员是否存在时系统自动调用该方法去判断
__unset($key)当类外部调用unset方法销毁一个私有变量时,调用该方法
__toString()当输出一个对象时调用该方法去构造字符串信息,需要返回值
__clone()当调用clone命令克隆一个对象时候调用该方法做差异化处理 $this指针指向副本 $that指向原本
__call($functionName,$args)处理调用对象内部方法不存在时的情况,程序不报错二接着往下运行

封装 类中的有些方法属性可以供外部直接调用,有的却不允许调用,封装性就是把对象的属性和方法隐蔽其细节。PHP的类访问权限有三种 public(公有)、peotected(受保护的)、private(私有),三者的区别为

    public 公有权限,允许该方法或属性能够被外部直接访问。如果没有限定符修饰 默认为 public

    private 私有权限 该方法或属性只能在内部被调用。并且不能被子类所继承。

    protected 受保护权限 该限定符是对 上述两种限定符的一种折中方案,不能被外部访问却可以被子类所继承,因为现实世界中我们既需要封闭细节又需要向后拓展。

多态 简单的讲多态就是具有相同行为的子类相对于父类或者其他子类的不同表现。还是以建筑蓝图举例,有些小区的建筑蓝图墙面粉饰需要铺墙砖,有的则为了彰显个性选择铺设墙纸,都是粉饰墙壁的行为,但是表现却不一样。多态的实现依赖于类中对行为的重写,如果父类可以被继承的情况下,行为没有被限定为final,表示该类的行为可以被重写,这样在子类中就有了不同的表现。

    可以通过继承实现多态

    可以通过接口实现多态

范围解析作用符 ::  用于访问类静态成员、属性和类常量,它们都被类实例对象说共享,另外self parent 调用也需要用::限定

对象操作符 -> 用于访问类实例化对象的属性和方法

demo示例

<?php
#声明抽象类命名空间为 Abs  类文件存放在Abs/Abs.php中 namespace Abs; #定义一个抽象类 但不是说抽象类就都是抽象方法 只是该类不能被实例化 需要子类去实现 abstract class Abs { #定义类常量 const VERSION = '1.0.0'; protected $msg; protected $time; protected $content; //声明一个public 的抽象方法 getMsg 没有函数体 abstract public function getMsg(); abstract public function updateData($content); //声明一个protected 的抽象方法 setTime 因为需要被子类继承 所以不能为private protected function setTime() { $this->time = date('Y-m-d H:i:s', time()); } function __construct() { self::dump("我是抽象类,命名空间为" . __NAMESPACE__ . " \n"); } #抽象类中也可以定义静态方法 为类所有对象所拥有 static public function method($message) { self::dump("我是静态方法 method ,所有对象都可以调用我,内部调用需要用self关键字加::调用我,外部需要用类名加::调用我 {$message} \n"); } #该方法手保护 不能被外部调用 static protected function dump($msg) { echo nl2br('当前版本:'.self::VERSION.$msg); } }
?>
<?php
#声明继承类命名空间为 Base  类文件存放在Base/Base.php中 namespace Base; use Abs\Abs; #定义一个实现类 实例化时需要知道 用extends 关键字 继承父类 class Base extends Abs { private $set = array(); //实现父类的抽象方法 public function getMsg() { #调用 $this 指针获取当前对象的内存地址 调用其方法 $this->setTime(); self::dump("我是 Base 中的getMsg()方法,输出内容:" . $msg . "输出时间:" . $this->time."\n"); } public function updateData($content) { $this->content = $content; } function __construct() { self::dump("我是Base构造函数,调用了父类的构造函数\n"); //调用父类的方法 用 parent 关键字 加 :: 限定符获取 parent::__construct(); self::dump("我是Base构造函数,命名空间为".__NAMESPACE__."\n"); } #新增一个类方法 并限定为最终方法 不能修改 final public function sayHello() { self::dump("Hello,我是sayHello方法,可以被外部调用,但是不允许重写我哟"); } #魔术set方法 function __set($key,$value){ self::dump("调用了set魔术方法{$key}:{$value}\n"); if (isset($this->set)) { $this->set[$key] = $value; } else { exit('not exist attr'); } } #魔术get方法 function __get($key) { if (isset($this->set)) { return $this->set[$key]; } else { return null; } } #魔术set方法 function __isset($key) { if (isset($this->set[$key])) { return true; } else { return false; } } #魔术unset方法 function __unset($key) { unset($this->set[$key]); } #魔术toString方法 function __toString() { self::dump("想把对象打印出来\n"); } #魔术clone方法 function __clone() { self::dump("调用了克隆命令\n"); } #魔术call方法 function __call($fname,$args) { self::dump("方法{$fname}不存在\n"); if ($args) { print_r($args); } } }
?>
<?php
#声明继承类命名空间为 Base  类文件存放在Base/BaseChild.php中 namespace Base; #定义一个实现类 实例化时需要知道 class BaseChild extends Base { function __construct() { self::dump("我是BaseChild构造函数,调用了父类的构造函数\n"); //调用父类的方法 用 parent 关键字 加 :: 限定符获取 parent::__construct(); self::dump("我是BaseChild构造函数,命名空间为" . __NAMESPACE__ . "\n"); } #如果尝试重写父类该方法 会报致命错误 Cannot override final method 如果是用final限定类 则不能被继承 可以去尝试下 // public function sayHello() { //  self::dump("Hello,我是sayHello的重写方法,可以被外部调用"); // } }
?>

调用代码

<?php
use Base\Base; #通过new 关键字 创建一个实例化一个类对象 返回对象句柄 $base = new Base(); Base::method('外部调用'); $base->name='kiity'; $base->age=28; $base->height='1.72m'; $base->boss='BAT'; var_dump($base->name); if (!isset($base->boss)) {     var_dump("boss value 不存在"); } else {     var_dump("boss value {$base->boss}");     #如果变量存在 销毁该变量     unset($base->boss);     var_dump($base->boss); } $base->callBack(1,2,'type'); $base2 = clone $base; print($base); #也可以实例化全路径类 获取对象 $child = new \Base\BaseChild(); //自动加载类的函数 function __autoload($className) {     $info = explode('\\',$className);     $path = './';     $length = count($info);     for ($i=0; $i <=$length-1 ; $i++) {          $path .=$info[$i];         if ($i!=$length-1) {             $path.="/";         }     }     $path .=".php";     if (!file_exists($path)) {         exit($className."不存在");     }     require_once $path; }
?>


搜索

关于楠Go

2015年毕业于吉林大学珠海学院,现今工作已两年有余,2014年在珠海一家游戏公司从事手机游戏开发,后离职转型为网络端PHP工程师,时至今日。熟练掌握PHP面向对象编程网络编程TP框架使用Discuz论坛插件开发。掌握前端框架Bootstrap的使用,掌握JS框架Jquery的使用。已开发多款网站,有着一定基础的开发经验,希望能在互联网领域再上一层楼!

了解更多: 开源中国 ThinkPHP


Powered by MetInfo 5.3.19 ©2008-2018 www.MetInfo.cn