开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
类与对象
# 成员:
类成员: 类常量、静态属性、静态方法
对象成员: 非静态属性、非静态方法
# 除此外,类不能包含任何其他东西!!!
# 类名、方法名、属性名均不区分大小写
# $this代表本对象,self代表本类,parent代表父类
# 类和函数均可被事先编译(仅作为最外层时)
# 类的定义必须在单一的PHP区块内,不能被多个PHP标签分割
构造方法
具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作(给类增加参数).
void __construct([ mixed $args [, $... ]] )
子类如果想继承父类的构造方法,要在子类的构造方法中调用 parent::__construct(),否则就是覆盖
析构方法
析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行.
void __destruct( void )
# 作用: 释放对象所占用的资源
# 调用的时机
- 脚本结束时所有资源均被释放,包括对象
- 手动删除对象时
- 保存对象的变量被赋予新值时(任何值,包括null)
- 在使用exit()终止脚本运行时也会被调用
静态成员
# static关键字
- 声明类成员或方法为static,就可以不实例化类而直接访问.
- 静态成员(属性或方法)均属于类,故不能通过$this或->访问.
- 静态成员是所有对象共享,属于类.
- 静态成员用类调用,非静态成员用对象调用.
# 静态属性
- 静态属性不可以由对象通过->操作符来访问.
- 静态属性只能被初始化为一个字符值或一个常量,不能使用表达式. 所以你可以把静态属性初始化为整型或数组,但不能指向另一个变量或函数返回值,也不能指向一个对象.
# 静态方法
- 由于静态方法不需要通过对象即可调用,所以伪变量$this在静态方法中不可用.
- 用::方式调用一个非静态方法会导致一个E_STRICT级别的错误.
访问解析操作符
::
- 可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法.
- 当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字.
- self 和 parent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的.
访问辨析
- 对象成员,内部通过$this指定,外部通过对象名指定,均用->访问,访问属性时不需加$.
对象名->属性名 对象名->方法名() $this->属性名 $this->方法名()
- 类成员,内部通过self或parent指定,外部通过类名指定,均用::访问,访问属性时需加$.
类名::$属性名 类名::方法名() self::$属性名 self::方法名()
- 特殊: 也可以通过对象访问类成员.(不建议)
对象名::$类属性名 $this::$类属性名 对象名::$类方法名() $this::类方法名()
# 对象成员访问用->,类成员访问用::
- 无论是静态方法还是非静态方法,均可通过类或对象进行访问.
- 静态属性通过类访问,静态方法通过对象访问.
- 只有使用对象调用非静态方法时,$this才可以使用!
- 静态方法不可使用$this.
- 类可以调用对象方法,但注意方法内不能有$this.
- 非静态方法可以调用静态属性或静态方法,反之不可以.
类常量
- 常量的值将始终保持不变.
- 在定义和使用常量的时候不需要使用$符号.
- 常量的值必须是一个定值,不能是变量,类属性或其它操作(如函数调用)的结果.
# 定义: const 常量名 = 常量值;
- 不需要加public等访问修饰限定符
- 类常量属于类,使用类访问,类名::类常量 或 self::类常量
自动加载对象
- 在试图使用尚未被定义的类时自动调用 __autoload 函数
- 自动加载使用到的类名文件(根据类名找相应名称的文件,故需类名与类文件名一致)
- 每个需要加载类的文件都需要存在__autoload函数
- 将__autoload函数写入单独的文件,每个需要用到类的文件再require该函数文件
- __autoload 参数是类名
function __autoload($class_name)
{
require_once $_SERVER["DOCUMENT_ROOT"] . "/class/$class_name.php";
}
序列化
# 数据传输均是字符串类型
# 除了资源类型,均可序列化
# 序列化在存放数据时,会存放数据本身,也会存放数据类型
作用: 1.在网络传输数据时;2.为了将数组或对象放在磁盘时
# 序列化
serialize 产生一个可存储的值的表示
string serialize ( mixed $value )
- 返回字符串,此字符串包含了表示value的字节流,可以存储于任何地方.
- 有利于存储或传递 PHP 的值,同时不丢失其类型和结构.
# 反序列化
unserialize 从已存储的表示中创建PHP的值
mixed unserialize ( string $str [, string $callback ] )
- 对单一的已序列化的变量进行操作,将其转换回PHP的值.
# 文件的读写操作
- file_put_contents 将一个字符串写入文件
int file_put_contents($file, $data [,$flags])
$flags: FILE_USE_INCLUDE_PATH(覆盖),FILE_APPEND(追加)
- file_get_contents 将整个文件读入一个字符串
string file_get_contents($file [, bool $use_include_path [,int $offset [,int $maxlen]]])
# 对象序列化
- 只能序列化对象内部的数据,即非静态属性.
# 需在反序列化对象之前加载类,也可以触发自动加载机制.
__sleep 序列化需序列化的属性.
- 提交未提交的数据,或类似的清理操作,部分串行化对象.
- 返回一个包含对象中所有应被序列化的变量名称的数组
__wakeup 反序列化时,预先准备对象需要的资源
- 重新建立数据库连接,或执行其它初始化操作
public function __sleep()
{
return array('server', 'username', 'password', 'db');
}
public function __wakeup()
{
$this->connect();
}
继承
class 子类名 extends 父类 {}
如果一个对象是子类的对象,那么同时也是父类的对象.
单继承: 一个类只能继承一个父类,不能同时继承多个类.但一个父类可以被多个子类继承.
instanceof 判断某对象是否为某类的对象
对象名 instanceof 类名
访问控制
public 公有的(继承链、本类、外部均可访问)
protected 保护的(仅继承链、本类可访问)
private 私有的(仅本类可访问)
根据成员定义位置、访问位置判断.
# 兼容性问题
- 声明属性时,var关键字声明的默认为public权限
- 声明方法时,省略访问修饰符,默认为public权限
重写
$this代表本对象,被谁调用,就代表哪个对象.
- 继承时,子类成员名于父类成员名发生冲突,则子类成员会重写父类成员.
- 属性和方法均可被子类重写.
- 当父类的方法或属性已经不满足子类的需求,则需要重写.
- 也可能因为命名不规范导致重写.
私有属性不能被重写,每个私有属性都会被记录.在记录属性名的同时,还会记录类.
如果有内置函数被重写,则可调用父类方法.如调用父类构造方法parent::__construct()
# 重写限制
访问限制:
子类的成员的访问控制必须相等或弱于父类.
方法参数限制:
参数数量必须相同,参数名可不同.
# $this确定原则
$this为调用该方法的对象,表示该方法的执行环境对象.
- 对象调用
- 环境的传递.如果当前调用时,不能确定$this的值(静态调用),此时静态调用所处对象环境会传递到被调用的方法内.
$this并非永远代表本对象,而是由方法的执行环境决定.
# final
如果父类中的方法被声明为final,则子类无法覆盖(重写)该方法.
如果一个类被声明为final,则不能被继承.
但加有final关键字的类依旧能被实例化!
# 抽象类
关键字: abstract
抽象类不能直接被实例化,必须先继承该抽象类,然后再实例化子类.
抽象类中至少要包含一个抽象方法.非抽象类不能包含抽象方法.
如果类方法被声明为抽象的,那么其中就不能包括具体的功能实现.抽象方法不能包含大括号及方法体.
继承一个抽象类的时候,子类必须实现抽象类中的所有抽象方法.
即,子类必须重写抽象父类中的所有抽象方法.
另外,这些方法的可见性必须和抽象类中一样(或者更为宽松).
即,如果抽象类中某个抽象方法被声明为protected,那么子类中实现的方法就应该声明为protected或者public,而不能定义为private.
- 抽象类的子类中的普通方法执行方式和其他类相同.
- 作用:
1. 继承,为扩展类,统一公共操作.
2. 限制结构(规范).规范子类的结构.
接口
关键字: interface
- 对象提供的与对象交互的方式就是接口.
- 使用接口可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容.
- 通过interface来定义一个接口,就像定义一个标准的类一样,但其中定义所有的方法都是空的.
- 接口中定义的所有属性和方法都必须是public,可省略public关键字.
- 接口中也可以定义常量(const).接口常量和类常量的使用完全相同.
可以用::访问.接口名::常量名,实现类::常量名.
它们都是定值,可以被子类或子接口使用,但不能修改.
- 接口不能定义属性!
# 定义接口
interface 接口名 {
接口内容(公共方法声明的集合)
}
# 接口实现
- 要实现一个接口,可以使用implements操作符.
- 类中必须实现接口中定义的所有方法,否则会报一个fatal错误.
- 如果要实现多个接口,可以用逗号来分隔多个接口的名称.
- 实现多个接口时,接口中的方法不能有重名.
- 接口也可以继承,通过使用extends操作符.
class 类名 implements 接口名
{
接口方法的实现
}
# 注意
1. 类与抽象类之间是继承关系,类与接口之间是实现关系.
2. 类与抽象类是单继承,类与接口是多实现.
3. 接口不是类,限制类的结构.
4. 接口与接口之间是多继承.用extends关键字.
interface I_C extends I_A, I_B {}
克隆
//对象之间的传值是[引用]传递.
克隆: 新对象 = clone 旧对象
- 所有的引用属性仍然会是一个指向原来的变量的引用.
__clone()方法在对象被克隆时自动调用.
注意: 构造方法对应实例化(new),克隆方法对应克隆(clone).
单例模式
#三私一公
单例模式(Singleton)用于为一个类生成一个唯一的对象.最常用的地方是数据库连接.使用单例模式生成一个对象后,该对象可以被其它众多对象所使用.
# 防止一个类被实例化多次
class MySQLDB
{
private static $instance = null; // 存类实例在此属性中
// 构造方法声明为private,防止直接创建对象
private function __construct() {}
public static function getInstance()
{
if(! self::$instance instanceof static) {
self::$instance = new static;
}
return self::$instance;
}
private function __clone() {} // 阻止用户复制对象实例
}
魔术方法
__construct 构造方法
__destruct 析构方法
__clone 克隆对象
__sleep 序列化对象
__wakeup 反序列化对象
__autoload 自动加载,使用类但未找到时
__toString 对象被当作字符串使用时
__invoke 当尝试以调用函数的方式调用一个对象时
关键字
this 代表本对象
public 公有的(继承链、本类、外部均可访问)
protected 保护的(仅继承链、本类可访问)
private 私有的(仅本类可访问)
parent:: 代表父类
self:: 代表本类(当前代码所在类)
static:: 代表本类(调用该方法的类)
static 静态成员(属性、方法),所有对象均可使用,外部也可直接使用或修改,静态方法不可访问非静态成员
final 方法用final不可被子类重载,类用final不可被继承(方法、类)
const 类常量(属性)
abstract 抽象类
interface 接口
extends 类继承(子接口继承接口、其他普通类继承)
implements 接口实现(类实现接口、抽象类实现借口)(对接口的实现和继承均可有多个)
Iterator 内置接口(迭代)
clone 克隆
instance 实例
instanceof 某对象是否属于某类
三大特性
封装: 隐藏内部是吸纳,仅开发接口.
继承: 一个对象的成员被另一个对象所使用.语法上体现为代码的共用.
多态: 多种形态.
流程控制
- if
if (条件判断) : 语句块; elseif (条件判断) : 语句块; else : 语句块; endif; //流程控制的替代语法 在嵌入HTML时常用 将 { 换成 : , 将 } 换成 endif; 等 endif endwhile endfor endforeach endswitch - while
while (expr) { statement } while (expr) : statement ... endwhile; 只要 while 表达式的值为 TRUE 就重复执行嵌套中的循环语句.表达式的值在每次开始循环时检查,所以即使这个值在循环语句中改变了,语句也不会停止执行,直到本次循环结束.有时候如果 while 表达式的值一开始就是 FALSE,则循环语句一次都不会执行 - for循环
for (条件初始化表达式; 条件判断表达式; 条件变化表达式) { 循环体 } 假设循环体被执行了N次,则 条件初始化表达式被执行1次 条件判断表达式被执行N+1次 条件变化表达式被执行N次 注意: 1. 循环变量在for语句结束后还可以继续使用,值为第一次失败的值 2. 循环变量在for循环体内可以使用 3. 任何条件表达式均可省略,但分号不能省略 a. 条件初始化表达式被省略时,循环变量被赋值为null,在与条件判断时, 进行类型转换后再比较.也可以在for语句外进行初始化. b. 条件判断表达式被省略时,表示循环为真,进入死循环 c. 条件变化表达式被省略时,可以在循环体内完成 4. 每个表达式均可由多条语句组成,每条语句之间使用逗号分割 如果条件判断表达式由多条语句组成,都会执行,但只有最后一条语句才作为判断条件 5. for只能遍历数值型索引下标数组 数组长度函数: count() 6. 应该将可以初始化的语句均放在条件初始化表达式内,这样可以省去很多执行次数 - foreach
foreach (array_expression as [$key =>] & $value) 当foreach开始执行时,数组内部的指针会自动指向第一个单元. 获取元素信息后,移动指针,再执行循环体 1. foreach本身循环结构,break和continue适用于foreach 2. foreach支持循环的替代语法. 3. $value是保存元素值的变量,对其修改不会改变数组的元素值 4. $value支持元素值的引用拷贝,在$value前加上&即可 5. $key不支持引用传递 6. foreach遍历的是原数组的拷贝,而在循环体对数组的操作是操作原数组 即循环体对数组的操作,对原数组生效,对遍历不生效. 先拷贝一份数组用作遍历 - break
break 可以接受一个可选的数字参数来决定跳出几重循环. $i = 0; while (++$i) { switch ($i) { case 5: echo "At 5<br />\n"; break 1; /* 只退出 switch. */ case 10: echo "At 10; quitting<br />\n"; break 2; /* 退出 switch 和 while 循环 */ default: break; } } - continue
continue 在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环. $i = 0; while ($i++ < 5) { echo "Outer<br />\n"; while (1) { echo "Middle<br />\n"; while (1) { echo "Inner<br />\n"; continue 3; } echo "This never gets output.<br />\n"; } echo "Neither does this.<br />\n"; } - switch
switch (条件) { case 状态值1: 语句块; [break;] case 状态值2: 语句块; [break;] case 状态值3: case 状态值4: 语句块; [break;] default: 语句块; [break;] } switch是状态分支,特殊的循环 先计算出状态值,再去与判断数作比较 break退出流程 - declare
- return
return与require结合,可返回文件的内容,return写在被载入的文件内
return可以终止所在脚本的执行,作为普通脚本语句
return可以返回函数的相应值
Note: 注意既然 return 是语言结构而不是函数,因此其参数没有必要用括号将其括起来.通常都不用括号,实际上也应该不用,这样可以降低 PHP 的负担.
Note: 如果没有提供参数,则一定不能用括号,此时返回 NULL.如果调用 return 时加上了括号却又没有参数会导致解析错误.
Note: 当用引用返回值时永远不要使用括号,这样行不通.只能通过引用返回变量,而不是语句的结果.如果使用 return (a) 的值(当然,此时该值也正是 $a 的值). - require require 在出错时产生 E_COMPILE_ERROR 级别的错误,程序不会继续运行
- include include 在出错时产生警告(E_WARNING),程序会继续运行.
- require_once require_once 语句和 require 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含.
- include_once 同上,确保它只被包含一次以避免函数重定义,变量重新赋值等问题.