PHP 的面向对象是很重要的内容,也是很常用的内容。所以现在就把 PHP 面向对象进行整理了一下。
顺带,我会在后面把我整理的一整套 CSS3,PHP,MYSQL 的开发的笔记打包放到百度云,有需要可以直接去百度云下载,这样以后你们开发就可以直接翻笔记不用百度搜那么麻烦了。
笔记链接:http://pan.baidu.com/s/1qYdQdKK 密码:pvj2
一、面向对象的基本概念
1. 什么是面向对象?
对象
面向
由于目前都还没有一个统一的概念,所以所能理解的就是一个物体被抽象出来,每个物品都是一个对象。
2. 什么是对象?
--- 世间万物皆对象
桌子、人、键盘……
看见的,看不见的(抽象的)
3. 对象的基本组成
对象包含两部分
- 对象的组成元素
· 是对象的数据模型,用于描述对象的数据
· 又被称为对象的属性,或者对象的成员变量
- 对象的行为
· 是对象的行为模型,用于描述对象能够做什么事情
· 又被称为对象的方法
4. 对象的特点
· 每个对象都是独一无二的
· 对象是一个特定事务,他的职能是完成特定功能
· 对象是可以重复使用的
5. 面向对象编程的基本概念
· 什么是面向对象?
- 面向就是在编程的时候一直把对象放在心上
· 面向对象编程就是在编程的时候数据结构(数据组织方式)都通过对象的结构进行存储
- 属性、方法
· 对象的描述方式更加贴合真实的世界,有利于大型业务的理解
· 在程序设计的过程中用对象的视角分析世界的时候能够独立拉近程序设计和真实世界的距离
6. 面向对象 -- 实质
· 面向对象就是把生活中要解决的问题都用对象的方式进行存储
- 属性
- 方法
· 对象与对象之间通过方法的调用完成互动
- 方法
7. 面向对象的基本思路
第一步:识别对象
- 任何实体都可以被识别为一个对象
第二步:识别对象的属性
- 对象里面存储的数据被识别为属性
- 对于不同的业务逻辑,关注的数据不同,对象里面存储的属性也不同
第三步:识别对象的行为
- 对象自己属性数据的改变
- 对象和外部交互
8. 面向对象的基本原则
对象内部是高内聚的
- 对象只负责一项特定的职能 (职能可大可小)
- 所有对象相关内容都封装到对象的内部
对象度外是低耦合的
- 外部世界可以看到对象的一些属性 (并非全部)
- 外部世界可以看到对象可以做某些事情 (并非全部)
二、PHP 中的面向对象编程
1. 面向对象基本实践
类的概念
- 类以物聚,把具有相似特性的对象归类到一个类中
- 类定义了这些相似对象拥有的相同的属性和方法
- 类是相似对象的描述,称为类的定义,是该类对象的蓝图或者原型
- 类的对象称为类的一个实例(类的实例化)
- 类的属性和方法统称为类成员
2. 类的实例化
类的实例化就是通过类定义创建一个类的对象
类的定义里面属性值都是空的,而对象的属性都具有具体的值
实例:
// 类的定义以关键字 class 开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束
- <?php
- date_default_timezone_set("PRC");
- // 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束
- class NbaPlayer{
- public $name="Jordan";
- public $height="198cm";
- public $weight="98kg";
- public $team="bull";
- public $playerNumber="23";
- // 默认构造函数,在对象被实例化的时候自动调用
- function __construct($name,$height,$weight,$team,$playerNumber){
- echo "In NbaPlayer constructor <br>";
- $this->name =$name;//$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法
- $this->height=$height;
- $this->weight=$weight;
- $this->team=$team;
- $this->playerNumber=$playerNumber;
- }
- // 定义方法
- public function run(){
- echo "Running\n";
- }
- public function jump(){
- echo "Jumping\n";
- }
- public function dribble(){
- echo "dribbling\n";
- }
- public function shoot(){
- echo "shooting\n";
- }
- public function dunk(){
- echo "dunking\n";
- }
- public function pass(){
- echo "passing\n";
- }
- // 析构函数,在程序执行结束的时候会自动调用
- //析构函数通常被用于清理程序使用的资源。比如程序使用了打印机,那么可以在析构函数里面释放打印机资源
- function __destruct(){
- echo "Destroying ".$this->name."<br>";
- }
- }
- //类到对象的实例化
- // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号
- $Jordan=new NbaPlayer("lihua","198cm","98kg","bull","23");
- // 对象中的属性成员可以通过->符号来访问
- echo $Jordan->name."<br>";
- echo $Jordan->height."<br>";
- // 对象中的成员方法可以通过->符号来访问
- $Jordan->dribble();
- $Jordan->pass()."<br>";
- $james=new NbaPlayer("James","213cm","100kg","heat","23");
- echo $james->name."<br>";
- //通过把变量设置为null 可以触发析构函数的调用
- $james=null;
- echo "From now on james will not be used<br>";
- ?>
三、面向对象高级实践
1. 面向对象 -- 继承
继承的好处:
- 父类里面定义的类成员可以不用在子类中重复定义,节约了编程的时间和代价
· 比如,人的吃这个方法一旦在父类汇总定义,那么 NBA 球员和女主播两个子类就不需要实现吃这个方法了,就好像天胜就有这个功能一样
- 同一个父类的子类拥有相同的父类定义的类成员,因此外部代码调用它们的时候可以一视同仁
· 比如 一个 NBA 球员和一个女主播,因为她们都是人,所以可以直接调用父类定义的 "吃" 方法,而不用管他到底是个 NBA 球员还是女主播
- 子类可以修改和调整父类定义的类成员
· 我们称为重写
· 一旦子类修改了,就按照子类修改之后的功能执行
实例:
- <?php
- class Human{
- public $name;
- public $height;
- public $weight;
- function eat($food){
- echo $this->name."'s eating ".$food."<br>";
- }
- }
- //在PHP中可以使用extends关键字来表示类的继承,后面跟父类的类名
- // PHP在extends后面只能跟一个类的类名,这就是PHP的单继承原则
- class NbaPlayer extends Human{
- public $team;
- public $playerNumber;
- function __construct($name,$height,$weight,$team,$playerNumber){
- $this->name =$name;
- $this->height=$height; //父类中的属性,可以通过$this来访问
- $this->weight=$weight;
- $this->team=$team;
- $this->playerNumber=$playerNumber;
- }
- }
- $Jordan=new NbaPlayer("jordan","198cm","98kg","bull","23");
- echo $Jordan->name."<br>";
- $Jordan->eat("chicken"); //在子类的对象上可以直接访问父类中定义的方法和属性
- ?>
2. 面向对象 -- 访问控制
· 面向对象的三种访问权限
-public 公有的类成员,可以在任何地方被访问
· 定义该成员的类(自身)、该类的子类、其他类
-protected 受保护的类成员,可以被其自身以及其子类访问
-private 私有的类成员,只能被自身访问
// 在大括号内的保护对象或是私有对象是可以随便访问的,但是不能在类的外面直接引用
实例:
- <?php
- class Human{
- public $name;
- protected $height; //自身和子类可以访问
- public $weight;
- private $human=true; //只能自身访问
- function eat($food){
- echo $this->name."'s eating ".$food."<br>";
- }
- // 可以这样让子类调用私有和保护的对象,这叫封装
- public function info(){
- echo $this->name.";".$this->height.";".$this->human."<br>";
- }
- }
- class NbaPlayer extends Human{
- public $team="bull";
- public $playerNumber="23";
- private $age="38";
- // 默认构造函数,在对象被实例化的时候自动调用
- function __construct($name,$height,$weight,$team,$playerNumber){
- echo "In NbaPlayer constructor <br>";
- $this->name =$name;//$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法
- $this->height=$height; //父类中的属性,可以通过$this来访问
- $this->weight=$weight;
- $this->team=$team;
- $this->playerNumber=$playerNumber;
- }
- function getAge(){
- echo $this->name."'s age is ".$this->age."<br>";
- }
- }
- //类到对象的实例化
- // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号
- $Jordan=new NbaPlayer("jordan","198cm","98kg","bull","23");
- echo $Jordan->name."<br>";
- $Jordan->eat("chicken"); //在子类的对象上可以直接访问父类中定义的方法和属性
- $Jordan->getAge();
- // echo $Jordan->height; //保护对象这样不能访问
- $Jordan->info();
- ?>
3. 面向对象 -- 静态成员
使用类的静态成员特性就可以达到这样的效果
-static 关键字
实例:
- <?php
- /*
- 1.静态属性用于保存类的共有数据
- 2.静态方法里面只能访问静态属性
- 3.静态成员不需要实例化对象就可以访问
- 4.类的内部可以通过self 或者static关键字访问自身静态成员
- 5.可以通过parent关键字访问父类的静态成员
- 6.可以通过类的名称在类定义外部访问静态成员
- */
- class Human{
- public $name;
- protected $height; //自身和子类可以访问
- public $weight;
- private $human=true; //只能自身访问
- public static $sValue = "this is parent static";
- function eat($food){
- echo $this->name."'s eating ".$food."<br>";
- }
- // 可以这样让子类调用私有和保护的对象,这叫封装
- public function info(){
- echo $this->name.";".$this->height.";".$this->human."<br>";
- }
- }
- //在PHP中可以使用extends关键字来表示类的继承,后面跟父类的类名
- // PHP在extends后面只能跟一个类的类名,这就是PHP的单继承原则
- // 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写。以中括号开始和结束
- class NbaPlayer extends Human{
- public $team="bull";
- public $playerNumber="23";
- private $age="38";
- // 静态属性定义时在访问控制关键字后面添加static关键字
- public static $president = "David Stern";
- // 静态方法定义
- public static function changePresident($newPrsdt){
- // 在类定义中使用静态成员的时候,用self或者static关键字后面跟着::操作符,即可。注意,在访问静态成员的时候,::后面需要跟$符号
- self::$president=$newPrsdt;
- // 使用parent关键字就能够访问父类的静态成员
- echo parent::$sValue;
- }
- // 默认构造函数,在对象被实例化的时候自动调用
- function __construct($name,$height,$weight,$team,$playerNumber){
- $this->name =$name;//$this是php里面的伪变量,表示对象自身。可以通过$this->的方式访问对象的属性和方法
- $this->height=$height; //父类中的属性,可以通过$this来访问
- $this->weight=$weight;
- $this->team=$team;
- $this->playerNumber=$playerNumber;
- }
- function getAge(){
- echo $this->name."'s age is ".$this->age."<br>";
- }
- }
- //类到对象的实例化
- // 类的实例化为对象使用关键字new,new之后紧跟类的名称和一对括号
- $jordan=new NbaPlayer("jordan","198cm","98kg","bull","23");
- $james=new NbaPlayer("james","210cm","98kg","heat","23");
- // $james->changePresident();这样会出错!
- // 在类定义外部访问静态属性,我们可以用类名加::操作符的方法来访问类的静态成员。
- echo NbaPlayer::$president."<br>";
- NbaPlayer::changePresident("Dam silver");//替换静态变量
- echo NbaPlayer::$president."<br>";//可以输出替换的变量
- echo Human::$sValue."<br>";
- ?>
4. 面向对象 --final 成员
使用类的 final 成员特性就可以达到这样的效果
-final 关键字
final 使用后就不能继承类或方法,并且方法不能在子类中被修改
实例:
- <?php
- //子类中编写跟父类方法名完全一致的方法可以完成对父类方法的重写(overwrite)
- // 对于不想被任何类继承的类可以在class之前添加final关键字
- // 对于不想被子类重写(修改)的方法,可以在方法定义的前面添加final关键字
- // 如果在baseclass前面添加final 那么这个类不能被继承
- class BaseClass{
- public function test(){
- echo "BaseClass::test <br>";
- }
- // 添加final关键字能够让这个方法不能够在子类中重写
- final public function test1(){
- echo "BaseClass::test1 <br>";
- }
- }
- class ChildClass extends BaseClass{
- public function test($temp=null){
- echo "ChildClass::test ".$temp."<br>";
- }
- /* 父类中的final给了test1()方法,而不能继承
- public function test1(){
- echo "ChildClass::test1 <br>";
- } */
- }
- $obj = new ChildClass();
- $obj->test("TMP");
- $obj->test1(); //可以继承父类中的test1()方法,但是不能改写
- ?>
5. 面向对象 -- 数据访问
实例:
- 实例: < ?php
- // 1.parent关键字可以用于调用父类中被子类重写了的方法
- // 2.self关键字可以用于访问类自身的成员方法,也可以用于访问自身的静态成员和类常量;
- //不能用于访问类自身的属性;使用常量的时候不需要在常量名称前面添加$符号
- //3.static关键字用于访问类自身定义的静态成员,防伪静态属性时需要在属性前面添加$符号
- class BaseClass {
- public
- function test() {
- echo "BaseClass::test <br>";
- }
- final public
- function test1() {
- echo "BaseClass::test1 <br>";
- }
- }
- class ChildClass extends BaseClass {
- // const为常量,不需要用$在前面
- private static $sValue = 'static value'; //这种叫伪静态
- const CONST_VALUE = 'A constant value';
- public
- function test($temp = null) {
- echo "ChildClass::test ".$temp."<br>";
- parent: :test(); //用parent关键字可以访问父类中被子类重写的方法 调用父类原来的test方法
- self: :called(); //可以用self调用自己这个类内的方法
- echo self: :CONST_VALUE."<BR>";
- echo self: :$sValue."<BR>";
- }
- final public
- function called() {
- echo "ChildClass::called() called <br>";
- }
- }
- $obj = new ChildClass();
- $obj - >test("TMP");
- // $obj->test1();
- ? >
6. 面向对象 -- 接口
问题:
- 人会吃饭,动物也会吃饭
- 有些植物也可以吃东西(比如猪笼草)
· 接口就是把不同类的共同行为进行了定义,然后在不同的类里面实现不同的功能
· 一旦某个类实现了某个接口,那么就必须实现接口定义的方法
· 人这个类实现了 "会吃东西" 这个接口,那么人必须实现接口定义的 "吃饭" 方法
· 某个类实现 (implements) 了某个接口和继承 (extends) 了某个类的区别
- 实现接口跟继承类很类似,但是接口不能直接创建自己的对象
· 如果创建了 "会吃东西" 这个接口的对象,那么具体怎么吃根本不知道
- 继承的父类必须有该方法的具体实现,子类可以重写父类的方法,也可以不重写
- 接口里面的方法是不需要具体实现的,只要定义了方法的名称和参数就可以了,具体的实现必须在实现类中定义
- 一句话概括:类的方法必须有实现,接口的方法必须为空
实例:
- <?php
- // interface关键字用于定义接口
- interface ICanEat{
- // 接口里面的方法不需要有方法的实现
- public function eat($food);
- }
- // implements关键字用于表示类实现某个接口
- class Human implements ICanEat{
- // 实现了某个接口之后,必须提供接口中定义的方法的具体实现
- public function eat($food){
- echo "Human eating ".$food."<br>";
- }
- }
- class Animal implements ICanEat{
- // 实现了某个接口之后,必须提供接口中定义的方法的具体实现
- public function eat($food){
- echo "Animal eating ".$food."<br>";
- }
- }
- $obj = new Human();
- $obj->eat("Apple");
- $monkey = new Animal();
- $monkey->eat("Banana");
- // 不能实例化接口
- // $eatObj = new ICanEat();
- // 可以用instanceof关键字来判断某个对象是否实现了某个接口
- var_dump($obj instanceof ICanEat);
- function checkEat($obj){
- if($obj instanceof ICanEat){
- $obj->eat('food');
- }else{
- echo "The obj can't eat<br>";
- }
- }
- // 相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态
- checkEat($obj);
- checkEat($monkey);
- // 可以用extends让接口继承接口
- interface ICanPee extends ICanEat{
- public function pee();
- }
- class Human1 implements ICanPee{
- public function pee(){
- echo "I can pee";
- }
- // 当继承一个接口的时候 也需要实现另一个接口中的方法
- // 当类实现子接口时,父接口定义的方法也需要在这个类里面实现
- public function eat($food){
- echo "Animal eating ".$food."<br>";
- }
- }
- ?>
7. 面向对象 -- 多态
因为接口的方法实现可以很多,所以对于接口里面定义的方法的具体实现是多种多样的,这种特性我们称为多态
- 比如接口 A 有两个实现 B 和 C,B 和 C 对 A 里面定义的方法的实现可以是不同的,这种现象就是多态。
实例:
- <?php
- function checkEat($obj){
- if($obj instanceof ICanEat){
- $obj->eat('food');
- }else{
- echo "The obj can't eat<br>";
- }
- }
- // 相同的一行代码,对于传入不同的接口的实现的对象的时候,表现是不同的,这就是多态
- checkEat($obj);
- checkEat($monkey);
- ?>
8. 面向对象 -- 抽象类
· 接口里面的方法都是没有实现的,而类里面的方法都是有实现的。
· 有没有一种形态,允许类里面一部分方法不实现呢?
- 当接口中的某些方法对于所有的实现类都是一样的实现方法,只有部分方法需要用到多态的特性
实例
- 人和动物吃东西是不同的,但是呼吸是相同的,不需要为人和动物分别实现呼吸的功能。
- 实例:(既有接口,里面又有类方法) < ?php
- // abstract关键字用于定义抽象类
- abstract class ACanEat {
- // 在抽象方法前面添加abstract关键字可以标明这个方法是抽象方法,不需要具体实现
- abstract public
- function eat($food);
- // 抽象类中可以包含普通的方法,有方法的具体实现
- public
- function breath() {
- echo "Breath use the air<br>";
- }
- }
- // 继承抽象类的关键字是extends
- class Human extends ACanEat {
- // 继承抽象类的子类需要实现抽象类中定义的抽象方法
- public
- function eat($food) {
- echo "Human eating".$food."<br>";
- }
- }
- class Animal extends ACanEat {
- public
- function eat($food) {
- echo "Animal eating".$food."<br>";
- }
- }
- $man = new Human();
- $man - >eat("Apple");
- $monkey = new Animal();
- $monkey - >eat("banana");
- $monkey - >breath(); //和Animal类共用了抽象类中的breath方法
- ? >
五、面向对象的特殊实践
1. 面向对象 -- 魔术方法
·__tostring()
- 当对象被当做 String 使用时,这个方法会被自动调用。
-Echo $obj;
·__invoke()
- 当对象被当成方法调用时,这个方法会被自动调用
-$obj(4);
实例:
- <?php
- class MagicTest{
- // __tostring会在把对象转换为string的时候自动调用
- public function __tostring(){
- return "this is tostring<br>";
- }
- // __inboke会在把对象当做一个方法调用的时候自动调用
- public function __invoke($x){
- echo "this is invoke ".$x."<br>";
- }
- }
- $obj = new MagicTest();
- echo $obj; //自动调用__tostring();
- $obj(5);//自动调用__invoke方法
- ?>
2. 面向对象 -- 魔术方法之 __call() 和__callStatic()
·__call()
- 当对象访问不存在的方法名称时,__call() 方法会被自动调用
·__callStatic()
- 当对象访问不存在的静态方法名称时,__callStatic() 方法会被自动调用
· 这两个方法在 PHP 里面也被称为方法的重载 (overloading)
- 注意区分重写 (overwrite)
- 通过这两个方法,同一个方法的名称的调用可以对应不同的方法实现
实例:
- <?php
- class MagicTest{
- // 这个方法的参数第一个就是调用的方法的名称,第二个参数是方法调用的参数组成的数组
- // implode 分割函数
- public function __call($name,$arguments){
- echo "Calling ".$name." with parameters ".implode(",",$arguments)."<br>";
- }
- // 静态方法的重载,注意这个方法需要设定为static
- public static function __callStatic($name,$arguments){
- echo "Static calling ".$name." with parameters ".implode(",",$arguments)."<br>";
- }
- }
- $obj = new MagicTest();
- $obj->runTest("para1","para2"); //自动调用__call方法
- MagicTest::runTest("para1","para2");//自动调用__call方法
- ?>
3. 面向对象 -- 魔术方法之 __get() 和__set(),__isset(),__unset()
- 在给不可访问属性赋值时,__set() 会被调用。
- 读取不可访问属性的值时,__get() 会被调用。
- 当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
- 当对不可访问属性调用 unset() 时,__unset() 会被调用
- 所谓不可访问属性,实际上就是在调用某个属性时发现这个属性没有被定义,这时候不同的操纵会触发不同的魔术方法
- 这几个方法也被成为属性重载的魔术方法
实例:
- <?php
- class MagicTest{
- public function __get($name){
- return "Getting the property ".$name."<br>";
- }
- public function __set($name,$value){
- echo "Setting the property ".$name." to value ".$value."<br>";
- }
- public function __isset($name){
- echo "__isset invoked<br>";
- return true;
- }
- public function __unset($name){
- echo "unsetting property".$name."<br>";
- }
- }
- $obj = new MagicTest();
- echo $obj->className."<br>";
- $obj->className="MagicClass";
- echo '$obj->className is set?'.isset($obj->className)."<br>";
- echo '$obj->className is empty?'.empty($obj->className)."<br>";
- unset($obj->className);
- ?>
4. 面向对象 -- 魔术方法之 __clone()
克隆方法(在没有设置对象的时候,会自动调用)
实例:(既有接口,里面又有类方法)
- 实例:
- <?php
- class NbaPlayer{
- public $name;
- function __clone(){
- $this->name = "TBD";
- }
- }
- $james = new NbaPlayer();
- $james->name="james";
- $james2=clone $james;
- echo "Before set up: James2's:".$james2->name."<br>";
- $james2->name="james2";
- echo $james->name."<br>";
- echo $james2->name."<br>";
- ?>
总的全部就是这么多了,上面还没有说到封装特性。其实封装就是把一个物体抽象出来后作为一个个体进行属性,方法做成一个类,然后流出对应的入口和出口,就叫封装了。
最后贴上笔记链接,有需要可以下载。
笔记链接:http://pan.baidu.com/s/1qYdQdKK 密码:pvj2
来源: http://www.cnblogs.com/leoyi330/p/7027346.html