PHP进阶之路 -- 02 面向对象
PHP进阶之路-- 之 “面向对象” 基础
- 概念
- 类的介绍和定义
- 类的属性
- 类常量
- 类的自动加载
- 构造函数和析构函数
- 访问控制
- 对象继承
- 范围解析操作符
- static静态关键字
- 抽象类
- 对象接口
- Trait
- 匿名类
- 遍历对象
- 魔术方法
- Final关键字
- 对象复制
一、概念
面向对象编程是很多编程语言的重头戏,对于php来讲,同样是支持面向对象的。在php5之后,对面向对象有了更加良好的支持。
掌握面向对象编程对于提高php编程能力和规划web开发架构具有很好的帮助。
在php中,想要掌握面向对象,需要先来弄清楚类和对象之间的关系。
二、类的介绍和定义
在php中,类是对象的基础,也可以说是对象的模型,没有类就没有对象。那么如何创建一个类呢?
创建类主要通过class关键字。每个类的定义都以关键字 class 开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。 类名可以是任何非 PHP 保留字的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。以正则表达式表示为:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*。
一个类可以包含有属于自己的常量,变量(称为“属性”)以及函数(称为“方法”)。
例如下面的代码,创建一个非常简单的类:
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 17:48
*/ class MyClass {
// 类中包含有属性 和 方法
public $name;
public $age; public function sayHello(){
echo "hello,world";
}
}
需要注意的是,在类中存在一个伪变量$this,这个伪变量是php提供给我们为了方便我们在类中调用自身属性或者方法而提供,$this是一个指向性的变量,它代指未来通过类创建出来的那个对象,简单点说就是谁变成了对象,这个$this就指向谁。
关于$this的具体用法可以看下面的例子:
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 17:48
*/ class MyClass {
// 类中包含有属性 和 方法
public $name;
public $age; public function sayHello(){
echo "hello,world";
}
public function test(){
$this->name = "张三"; // 设置属性值
}
}
三、类的属性
类的变量成员叫做“属性”,或者叫“字段”、“特征”,在本文档统一称为“属性”。属性声明是由关键字 public,protected 或者 private 开头,然后跟一个普通的变量声明来组成。属性中的变量可以初始化,但是初始化的值必须是常数,这里的常数是指 PHP 脚本在编译阶段时就可以得到其值,而不依赖于运行时的信息才能求值。
在类的成员方法里面,可以用 ->(对象运算符):$this->property(其中 property 是该属性名)这种方式来访问非静态属性。静态属性则是用 ::(双冒号):self::$property 来访问。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 17:48
*/ class MyClass {
//属性
public $name;
protected $age;
private $like;
public static $info; }
四、类常量
可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 17:48
*/ class MyClass { const hello = "hello,world"; // 类常量 // 在方法中调用类常量
public function getCon(){
echo self::hello;
} }
五、类的自动加载
在编写面向对象(OOP) 程序时,很多开发者为每个类新建一个 PHP 文件。 这会带来一个烦恼:每个脚本的开头,都需要包含(include)一个长长的列表(每个类都有个文件)。
在 PHP 5 中,已经不再需要这样了。 spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 17:48
*/ spl_autoload_register(function($className){
require_once $className . ".php";// 需要注意的是,如果想要通过这种方式加载,那么类名必须和文件名相同
}); $obj = new MyClass();
$obj->sayHello(); #==============================================
//MyClass.php
class MyClass {
public function sayHello(){
echo "hello,world";
}
}
六、构造函数和析构函数
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
需要注意的是,构造函数通常情况下我们用来进行初始化工作,同时构造函数的执行时机是类实例化生成对象执行自动执行。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:06
*/ // 构造函数和析构函数
class MyClass { // 假设我们的属性并没有初始化
public $name; // 那么我们就可以在构造函数中进行初始化
public function __construct($name)
{
$this->name = $name; // 对类的属性进行初始化
} public function __destruct()
{
// TODO: Implement __destruct() method.
echo "我是在回收销毁之前执行哦";
}
} // 因为我们设置了构造函数,并且让构造函数进行初始化操作,那么我们在实例化的时候,就需要传入值
$obj = new MyClass("张三");
我们在使用构造函数和析构函数的时候需要注意的地方就是二者的执行时机,构造函数在实例化的时候会执行,而析构函数会在回收销毁时执行。
七、访问控制
对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问。被定义为受保护的类成员则可以被其自身以及其子类和父类访问。被定义为私有的类成员则只能被其定义所在的类访问。
php作为一门服务端语言,代码的严谨性是直接与web站点的安全挂钩,所以说你写的代码是否足够强壮(安全),就决定了你的网站安全程度,而访问限制就是保证代码强壮的因素之一。
<?php
class MyClass { // 创建属性
public $name;
protected $age;
private $sex; // 创建方法
// 构造方法通常情况下是public权限
public function __construct($name,$age,$sex) // 对属性进行初始化
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
// 受保护的权限,只能够在本类和子类中使用
protected function sayHello(){
echo "hello,world";
}
// 私有权限,只能够在本类中使用
private function test(){
echo "this is test";
}
}
八、对象继承
继承已为大家所熟知的一个程序设计特性,PHP 的对象模型也使用了继承。继承将会影响到类与类,对象与对象之间的关系。
比如,当扩展一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:16
*/ // 对象继承
class Base {
public $info; public function __construct($info)
{
$this->info = $info;
}
} // 创建子类继承 -- 子类会无条件继承父类的所有的属性和方法
class MyClass extends Base { // 如果当子类中的方法与父类相同,那么子类的方法会覆盖掉父类的方法
public function __construct($info) // 此时子类的构造函数会覆盖掉父类的构造函数
{
// 如果想要使用父类的构造函数,需要如下
parent::__construct($info);
}
} $obj = new MyClass('hello');
九、范围解析操作符
范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。
当在类定义之外引用到这些项目时,要使用类名。self,parent 和 static 这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的。
例如我们上面在类的方法使用父类的方法,可以使用parent::MethodName ,例如我们想要调用静态变量,可以是self::$StaticName。
十、static静态关键字
声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。
就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:31
*/ class MyClass {
// 创建一个静态属性
public static $info = "php is the best language in the world"; // 创建一个静态方法,并且调用这个静态属性
public static function test(){
echo self::$info;
}
}
十一、抽象类
PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:31
*/ // 抽象类
abstract class AbstractClass {
// 抽象类中的方法会强制要求子类去实现
abstract protected function Run();
abstract protected function Song(); // 抽象类中同样可以存在普通的方法
public function hello(){
echo "hello,world";
}
} // 定义普通类并且继承抽象类
class MyClass extends AbstractClass {
// 子类中的权限必须跟父类相同或者更加宽松
public function Run()
{
// TODO: Implement Run() method.
echo "running....";
}
public function Song()
{
// TODO: Implement Song() method.
echo "唱歌ing...";
}
} // 实例化子类
$obj = new MyClass();
$obj->Run();
$obj->Song();
$obj->hello();
十二、 对象接口
使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
接口中定义的所有方法都必须是公有,这是接口的特性。
要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。
接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:40
*/ // 接口
interface Hello { // 定义一个接口,接口权限必须全部是公开的
public function sayHello($name);
} // 通过类来实现接口
class MyClass implements Hello{
public function sayHello($name)
{
// TODO: Implement sayHello() method.
echo "你好,{$name}";
}
}
十三、Trait
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:44
*/ // trait 实现代码复用
trait Hello {
public function HelloWorld() {
echo "hello,world!";
}
public function HelloPhp(){
echo "hello,php!";
}
public function HelloHow(){
echo "how are you ?";
}
} // 创建一个类并且使用hello
class MyClass {
// 我们在这个类中想要实现打招呼的功能
use Hello;
} class MyClassTwo {
use Hello; // 第二次使用Hello trait
} $obj = new MyClass();
$obj2 = new MyClassTwo(); $obj->HelloHow();
$obj2->HelloWorld();
十四、匿名类
PHP 7 开始支持匿名类。 匿名类很有用,可以创建一次性的简单对象。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:50
*/
class MyClass {}
interface Test {}
trait TestTrait {} var_dump(new class(10) extends MyClass implements Test {
private $name; public function __construct($num)
{
$this->num = $num;
} use TestTrait;
}); ##################################
# 打印结果
#object(class@anonymous)#1 (2) {
# ["name":"class@anonymous":private]=>
# NULL
# ["num"]=>
# int(10)
# }
###################################
匿名类被嵌套进普通 Class 后,不能访问这个外部类(Outer class)的 private(私有)、protected(受保护)方法或者属性。 为了访问外部类(Outer class)protected 属性或方法,匿名类可以 extend(扩展)此外部类。 为了使用外部类(Outer class)的 private 属性,必须通过构造器传进来:
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 18:56
*/ // 匿名类
class MyClass { private $num = 10; public function testFunc(){
return new class($this->num) extends MyClass { //想要访问外部受保护的属性或者方法需要继承外部类
private $prop3; public function __construct($num) // 处在类方法里面的匿名类想要调用上级属性,需要通过构造函数传值的形式传入
{
$this->prop3 = $num;
}
};
} }
十五、遍历对象
在php中,遍历对象,我们可以采用foreach方法。通过foreach方法所有的可见属性都可以被遍历出来。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 19:44
*/ class MyClass {
public $name = "Java";
public $info = "java 和 php "; public function sayBye(){
echo "我爱php,再见java";
}
} $obj = new MyClass(); foreach($obj as $key=>$value){
echo "$key=>$value";
}
十六、魔术方法
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
通常情况下,魔术方法不需要显示的调用。
具体介绍:http://php.net/manual/zh/language.oop5.magic.php
十七、Final关键字
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
<?php
/**
* Created by PhpStorm.
* User: liujunhang
* Date: 2018/6/18
* Time: 19:44
*/ class MyClass { public function test(){ // 类中的普通方法
echo "test .....";
} final public function test2(){
echo "final method ..."; // final方法
}
} // 子类继承
class MyTemplete extends MyClass {
// 覆盖父类的final方法
public function test2() {
// 执行就会报 Cannot override final method MyClass::test2()
}
} $obj = new MyTemplete();
$obj->test(); // test ......
$obj->test2(); // final method ... 可以使用父类的final方法 ,但是一旦进行覆盖则会报错
十八、对象复制
对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。
语法: $copy_of_object = clone $object;
当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。
<?php
header("Content-type:text/html;Charset=utf-8"); // 创建一个对象,并且进行复制操作
class MyClass {
public $info = <<<TEST:
Name: 张三
Phone:13889893432
Address:上海静安区万荣路1188号
TEST:; public function Running(){
echo "running.....";
} }
// 将这个对象实例化,并且进行克隆
$obj = new MyClass();
$test= clone $obj;
//var_dump($test); $test->hello = "hello,PHP"; // 克隆对象新增加了一个属性 ,打印后发现原对象并没有增加,克隆对象增加
//var_dump($obj);
//var_dump($test); $obj->info="info替换更改"; // 当原对象发生更改的时候,克隆对象并没有发生更改
var_dump($obj);
var_dump($test); ?>
PHP进阶之路 -- 02 面向对象的更多相关文章
- 从零到Django大牛的的进阶之路02
Cookie/Session Cookie Cookie以键值对的格式进行信息的存储. Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Coo ...
- GO语言的进阶之路-面向对象编程
GO语言的进阶之路-面向对象编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 当你看完这篇文章之时,我可以说你的Golang算是入门了,何为入门?就是你去看Docker 源码能看 ...
- Scala进阶之路-面向对象编程之类的成员详解
Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...
- JavaScript进阶之路(一)初学者的开始
一:写在前面的问题和话 一个javascript初学者的进阶之路! 背景:3年后端(ASP.NET)工作经验,javascript水平一般般,前端水平一般般.学习资料:犀牛书. 如有误导,或者错误的地 ...
- 2017PHP程序员的进阶之路
2017PHP程序员的进阶之路 又是一年毕业季,可能会有好多毕业生即将进入开发这个圈子,踏上码农这个不归路.根据这些年在开发圈子总结的LNMP程序猿发展轨迹,结合个人经验体会,总结出很多程序员对未来的 ...
- 处女作《Web全栈开发进阶之路》出版了!
书中源码下载地址:https://github.com/qinggee/WebAdvanced 01. 当初决定写博客的原因非常的纯洁:只要每个月写上 4 篇以上博客,月底的绩效奖金就多 500 块. ...
- Scala进阶之路-Scala中的Ordered--Ordering
Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...
- Scala进阶之路-并发编程模型Akka入门篇
Scala进阶之路-并发编程模型Akka入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Akka Actor介绍 1>.Akka介绍 写并发程序很难.程序员不得不处 ...
- GO语言的进阶之路-网络编程之socket
GO语言的进阶之路-网络编程之socket 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是socket; 在说socket之前,我们要对两个概念要有所了解,就是IP和端口 ...
随机推荐
- SpringData JPA 在解析实体类字段时驼峰自动添加下划线问题
参考地址:https://my.oschina.net/javamaster/blog/2246886 SpringData JPA 使用的默认命名策略是: ImprovedNamingStrateg ...
- loj2718 「NOI2018」归程[Kruskal重构树+最短路]
关于Kruskal重构树可以翻阅本人的最小生成树笔记. 这题明显裸的Kruskal重构树. 然后这题限制$\le p$的边不能走,实际上就是要满足走最小边权最大的瓶颈路,于是跑最大生成树,构建Krus ...
- java面试题(目录版)
在https://www.cnblogs.com/marsitman/p/9539369.html 根据自己以往的面试经验,在该基础上做了补充和删减,均链接到相应的地址(链接失效请留言评论). 一. ...
- MariaDB安装与使用
下载地址:https://downloads.mariadb.org/ 下载相对应的电脑版本程序 等待下载完成...... 安装教程: 双击运行 设置数据库的密码 等待安装完成.. 这样就完成安装了. ...
- HDU-3613-Best Reward(Manacher, 前缀和)
链接: https://vjudge.net/problem/HDU-3613 题意: After an uphill battle, General Li won a great victory. ...
- (转)rotatelogs - Piped logging program to rotate Apache logs
原文:http://publib.boulder.ibm.com/httpserv/manual60/programs/rotatelogs.html rotatelogs is a simple p ...
- web上传整个文件夹
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...
- 关于java代理(静态代理和动态代理)
参考文章:http://kuangbaoxu.iteye.com/blog/193240
- MessagePack Java Jackson 在不关闭输入流(input stream)的情况下反序列化多变量
com.fasterxml.jackson.databind.ObjectMapper 在读取输入流变量的时候默认的将会关闭输入流. 如果你不希望关闭输入流,你可以设置 JsonParser.Feat ...
- ACM之一个简单的数学问题
一个简单的数学题 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 zyc最近迷上了数学,一天,dj想出了一道数学题来难住他.算出1/n,但zyc一时答不上来希望大家能编程 ...