类和对象
类是面向对象程序设计的基本概念,通俗的理解类就是对现实中某一个种类的东西的抽象
比如汽车可以抽象为一个类,汽车拥有名字、轮胎、速度、重量等属性,可以有换挡、前进、后退等操作方法。
对象通过new关键字进行实例化类
class Car {
}
$car = new car();实例化
类的属性
在类中定义的变量称之为属性,通常属性跟数据库中的字段有一定的关联,因此也可以称作“字段”。
属性声明是由关键字 public,protected 或者 private 开头,后面跟一个普通的变量声明来组成。属性的变量可以设置初始化的默认值,默认值必须是常量
class Car {
//定义公共属性
public $name = '汽车';
//定义受保护的属性
protected $corlor = '白色';
//定义私有属性
private $price = '100000';
}
1.默认都为public,外部可以访问。一般通过->对象操作符来访问对象的属性或者方法,
对于静态属性则使用::双冒号进行访问。
当在类成员方法内部调用的时候,可以使用$this伪变量调用当前对象的属性。
2.受保护的属性与私有属性不允许外部调用,在类的成员方法内部是可以调用的
类的方法
方法就是在类中的function
在面向过程的程序设计中function叫做函数,在面向对象中function则被称之为方法。
同属性一样,类的方法也具有public,protected 以及 private 的访问控制
class Car {
public function getName() {
return '汽车';
}
}
$car = new Car();
echo $car->getName();
使用关键字static修饰的,称之为静态方法
静态方法不需要实例化对象,可以通过类名直接调用,操作符为双冒号::
class Car {
public static function getName() {
return '汽车';
}
}
echo Car::getName(); //结果为“汽车”
类的方法之构造函数和析构函数
构造函数:实例化的时候 会自动调用构造函数__construct
class Car {
public function __construct() {
print "构造函数被调用\n";
}
}
$car = new Car();
调用继承父类的构造函数使用parent::__construct()显式的调用。
class Truck extends Car {
function __construct() {
print "子类构造函数被调用\n";
parent::__construct();
}
}
$car = new Truck();
析构函数指的是当某个对象的所有引用被删除,或者对象被显式的销毁时会执行的函数。
class Car {
function __construct() {
print "构造函数被调用 \n";
}
function __destruct() {
print "析构函数被调用 \n";
}
}
$car = new Car(); //实例化时会调用构造函数
echo '使用后,准备销毁car对象 \n';
unset($car); //销毁时会调用析构函数
类的关键字static
静态属性与方法可以在不实例化类的情况下调用,直接使用类名::方法名的方式进行调用。静态属性不允许对象使用->操作符调用。
class Car {
private static $speed = 10;
public static function getSpeed() {
return self::$speed;
}
}
echo Car::getSpeed(); //调用静态方法
静态方法中,$this伪变量不允许使用。可以使用self,parent,static在内部调用静态方法与属性。
访问控制
访问控制通过关键字public,protected和private来实现。
1.被定义为 公有的类 成员可以在任何地方被访问。
2.被定义为 受保护的类 成员则可以被其自身以及其子类和父类访问。
3.被定义为 私有的类 成员则只能被其定义所在的类访问。
重载
PHP中的重载指的是动态的创建属性与方法,是通过魔术方法来实现的。
- 属性重载:
通过__set,__get,__isset,__unset来分别实现对不存在属性的赋值、读取、判断属性是否设置、销毁属性。
class Car {
private $ary = array();
public function __set($key, $val) {
$this->ary[$key] = $val;
}
public function __get($key) {
if (isset($this->ary[$key])) {
return $this->ary[$key];
}
return null;
}
public function __isset($key) {
if (isset($this->ary[$key])) {
return true;
}
return false;
}
public function __unset($key) {
unset($this->ary[$key]);
}
}
$car = new Car();
$car->name = '汽车'; //name属性动态创建并赋值
echo $car->name; //汽车
- 方法重载:
通过__call来实现,当调用不存在的方法的时候,将会转为参数调用__call方法,当调用不存在的静态方法时会使用__callStatic重载。
class Car {
public $speed = 0;
public function __call($name, $args) {
if ($name == 'speedUp') {
$this->speed += 10;
}
}
}
$car = new Car();
$car->speedUp(); //调用不存在的方法会使用重载
echo $car->speed; //10
对象高级特性
- 对象比较
1.当同一个类的两个实例的所有属性都相等时,可以使用比较运算符==进行判断,
2.当需要判断两个变量是否为同一个对象的引用时,可以使用全等运算符===进行判断。
class Car {
}
$a = new Car();
$b = new Car();
if ($a == $b) echo '=='; //true
if ($a === $b) echo '==='; //false
- 对象复制
关键字clone来复制一个对象,这时__clone方法会被调用,通过这个魔术方法来设置属性的值。
class Car {
public $name = 'car';
public function __clone() {
$obj = new Car();
$obj->name = $this->name;
}
}
$a = new Car();
$a->name = 'new car';
$b = clone $a;
var_dump($b);
object(Car)#2 (1) {
["name"]=>
string(7) "new car"
}
- 对象序列化
serialize方法将对象序列化为字符串,用于存储或者传递数据
通过unserialize将字符串反序列化成对象进行使用
class Car {
public $name = 'car';
}
$a = new Car();
$str = serialize($a); //对象序列化成字符串
echo $str.'<br>';
$b = unserialize($str); //反序列化为对象
var_dump($b);
异常处理
基本语法
try{
//可能出现错误或异常的代码
//catch表示捕获,Exception是php已定义好的异常类
} catch(Exception $e){
//对异常处理,方法:
//1、自己处理
//2、不处理,将其再次抛出
}
既然抛出异常会中断程序执行,那么为什么还需要使用异常处理?
异常抛出被用于在遇到未知错误,或者不符合预先设定的条件时,通知客户程序,以便进行其他相关处理,不至于使程序直接报错中断。
异常处理类
Exception是所有异常处理的基类。
Exception具有几个基本属性与方法:
- message 异常消息内容
- code 异常代码
- file 抛出异常的文件名
- line 抛出异常在该文件的行数
常用方法:
getTrace 获取异常追踪信息
getTraceAsString 获取异常追踪信息的字符串
getMessage 获取出错信息
只有在极端情况或者非常重要的情况下,才会抛出异常
一般的异常处理流程代码为:
try {
throw new Exception('wrong');
} catch(Exception $ex) {
$msg = 'Error:'.$ex->getMessage()."\n";
$msg.= $ex->getTraceAsString()."\n";
$msg.= '异常行号:'.$ex->getLine()."\n";
$msg.= '所在文件:'.$ex->getFile()."\n";
//将异常信息记录到日志中
PHP异常处理之 file_put_contents('error.log', $msg);
}
echo '异常处理后,继续执行其他代码';
正则表达式
正则匹配模式
PCRE库函数
正则匹配模式使用分隔符与元字符组成,分隔符可以是非数字、非反斜线、非空格的任意字符。
分隔符是正斜线(/)、hash符号(#) 、以及取反符号(~)
/foo bar/
#^[^0-9]$#
~php~
元字符
常用元字符
\ 一般用于转义字符
^ 断言目标的开始位置(或在多行模式下是行首)
$ 断言目标的结束位置(或在多行模式下是行尾)
. 匹配除换行符外的任何字符(默认)
[ 开始字符类定义
] 结束字符类定义
| 开始一个可选分支
( 子组的开始标记
) 子组的结束标记
? 作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。 (查阅量词)
* 量词,0 次或多次匹配
+ 量词,1 次或多次匹配
{ 自定义量词开始标记
} 自定义量词结束标记
以下来自PHP5权威编程
静态属性
属于类本身而非是类的实例
相当于是存储在类的全局变量,可以通过类在任何地方访问
由关键字 static定义
访问:
类名::定义静态名
Person:: $name
静态方法
访问:class_name::method
常量
与静态成员类似 属于类的本身不是属于类的实例
访问:self::常量名[规范大写]
self:: parent::
self 指向当前的类 用于访问静态属性、方法、常量
parent 指向父类 用于调用父类的构造函数和方法
instance of 逻辑二元运算符
用于确定一个 PHP 变量是否属于某一类 [class]
_CLASS_ 用于存储当前类名
Abstract 抽象方法和抽象类
抽象类不能够被实例化/初始化,但是可以依靠具体类的继承来实现。
继承的子类必须实现了抽象类中的所有抽象方法,否则会报错
如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化
定义:
class 前加了 abstract 关键字且存在抽象方法
(在类方法 function 关键字前加了 abstract 关键字)的类。
abstract class A
{
/** 抽象类中可以定义变量 */
protected $value1 = 0;
private $value2 = 1;
public $value3 = 2;
/** 也可以定义非抽象方法 */
public function my_print()
{
echo "hello,world/n";
}
/**
* 大多数情况下,抽象类至少含有一个抽象方法。
抽象方法用abstract关键字声明,其中不能有具体内容。
* 可以像声明普通类方法那样声明抽象方法,
但是要以分号而不是方法体结束。
也就是说抽象方法在抽象类中不能被实现,也就是没有函数体“{some codes}”。
*/
abstract protected function abstract_func1();
abstract protected function abstract_func2();
}
//部分继承抽象类A,且不能实例化
abstract class B extends A
{
public function abstract_func1()
{
echo "implement the abstract_func1 in class A/n";
}
/** 这么写在zend studio 8中会报错
//abstract protected function abstract_func2();
遵循以下规则:
B类的成员访问控制不能比A类严格
A->public B->public
A->protected B->public、protected
A不能定义为 private
( Fatal error : Abstract function A::abstract_func() cannot be declared private )
*/
}
class C extends B
{
public function abstract_func2()
{
echo "implement the abstract_func2 in class A/n";
}
}
interface 接口
参考文章:
interface abstract 不同点和相同点参考文章
interface 是完全抽象的,只能声明方法,而且只能声明 public 的方法,不能声明 private 及 protected 的方法,不能定义方法体,也不能声明实例变量 。然而, interface 却可以声明常量变量
interface iA
{
const AVAR=3;
public function iAfunc1();
public function iAfunc2();
}
echo iA:: AVAR;
任何实现接口的类都要实现接口中所定义的所有方法,否则要声明为abstract类
class E implements iA
{
public function iAfunc1(){echo "in iAfunc1";}
public function iAfunc2(){echo "in iAfunc2";}
}
abstract class E implements iA{}
类可以在声明中使用 implements 关键字来实现某个接口
interface iB
{
public function iBfunc1();
public function iBfunc2();
}
class D extends A implements iA,iB
{
public function abstract_func1()
{
echo "implement the abstract_func1 in class A/n";
}
public function abstract_func2()
{
echo "implement the abstract_func2 in class A/n";
}
public function iAfunc1(){echo "in iAfunc1";}
public function iAfunc2(){echo "in iAfunc2";}
public function iBfunc1(){echo "in iBfunc1";}
public function iBfunc2(){echo "in iBfunc2";}
}
类可以同时继承一个父类和实现任意多个接口
class D extends B implements iA,iB
{
public function abstract_func1()
{
parent::abstract_func1();
echo "override the abstract_func1 in class A/n";
}
public function abstract_func2()
{
echo "implement the abstract_func2 in class A/n";
}
public function iAfunc1(){echo "in iAfunc1";}
public function iAfunc2(){echo "in iAfunc2";}
public function iBfunc1(){echo "in iBfunc1";}
public function iBfunc2(){echo "in iBfunc2";}
}
final方法和类
final方法:确保一个方法不被继承类改写
final类:确保一个类不被继承