目录
0x00 类的声明
class 类名{
修饰符 成员变量
[修饰符] 成员函数
}
例如:
声明类时可以给成员变量赋值,也可以不赋值。
<?php
class Car{
var $color = 'red';
var $leg = 4;
public $person = 7;
function run(){
echo '跑';
}
function push(){
echo '拉'.$this->person.'人';
}
}
$car = new Car;
echo $car->color;
?>
成员变量的修饰符:
成员变量前必须有修饰符!
var /public:公有变量,任何地方都可以访问。
private:私有变量,只有成员函数可以访问。也就是说私有变量不会被继承。
protected:保护变量,只有成员函数和子类可以访问。
成员函数可以不写修饰符,默认为public
0x01 类的实例化:
1.new 类名(参数1,参数2)
2.new 类名
3.new 类名()
底层:
每次实例化其实都是在堆内存中开一段内存来存储对象的数据,而对象名存储在栈内存段,指向堆内存中相应的数据,需要注意的是堆内存中只存成员函数名,指向存储在代码段的成员函数的代码。
0x02 成员变量的访问
注意:成员变量前不需要加$符
<?php
echo $car->leg;
echo $car->push();
?>
0x03 $this
在成员方法中调用成员属性,必须加$this
0x04构造和析构方法
1.构造方法:在类实例化的时候自动调用,初始化类
写法一:
[public] function __construct([参数]){
}
写法二:与类名相同的函数,在PHP7中已经废弃
[public] function 类名([参数]){
xxxx
}
<?php
class Car{
var $color ;
var $leg;
public $person;
/*
function __construct(){
echo '无参构造'.'<br/>';
$this->color = 'red';
$this->leg = 10;
$this->person = 100;
}
*/
public function __construct($_color,$_leg,$_person){
echo '有参构造'.'<br/>';
$this->color = $_color;
$this->leg = $_leg;
$this->person = $_person;
}
public function __destruct(){
echo '析构函数';
}
public function show(){
echo 'color:'.$this->color.'<br/>';
echo 'leg:'.$this->leg.'<br/>';
echo 'person'.$this->person.'<br/>';
}
}
$car = new Car('green',4,120);
$car->show();
?>
2.析构方法:在对象被销毁时自动调用,用于资源的关闭,销毁文件句柄,或者链接。
public function __destruct(){
}
0x05 面向对象三大特性:封装 继承 多态
1.封装体现在两点:
- 把属性和方法封装到类中,实现某种功能
- 属性和方法前加修饰符,进行访问的限制
2.继承
(1)子类的定义方法:
class 子类名 extends 父类名{
}
子类继承父类之后,子类的对象继承了父类的所有方法和属性。
(2)子类调用父类的方法
如果子类想要在成员函数中调用父类的成员方法,只需要这样写:
parent::父类的方法
虽然调用的父类的方法,但是PHP将使用当前类的属性值。
(3)覆盖
在子类中可以重载父类的方法,即子类的同名方法将覆盖父类的同名方法
注意:重载后的方法必须不能比原来的方法的修饰符小 private < protected < public
<?php
class Car{
var $color ;
var $leg;
public $person;
public function __construct($_color,$_leg,$_person){
echo '有参构造'.'<br/>';
$this->color = $_color;
$this->leg = $_leg;
$this->person = $_person;
}
public function __destruct(){
echo '析构函数';
}
public function show(){
echo 'color:'.$this->color.'<br/>';
echo 'leg:'.$this->leg.'<br/>';
echo 'person'.$this->person.'<br/>';
}
}
class Truck extends Car{
var $capacity;
var $speed;
public function __construct($color,$leg,$person,$capacity,$speed){
echo '子类的构造函数';
parent::__construct($color,$leg,$person);
$this->capacity = $capacity;
$this->speed = $speed;
}
public function show(){
parent::show();
echo 'capacity:'.$this->capacity.'<br/>';
echo 'speed:'.$this->speed.'<br/>';
}
public function push(){
echo '我的最大载重为'.$this->capacity.'<br/>';
}
}
$car = new Car('green',4,120);
$car->show();
$cyber_truck = new Truck('gray',8,10,100,2000);
$cyber_truck->show();
$cyber_truck->push();
?>
(4)final关键字:
final function 函数名(){
}
表示该成员函数是最终版本,子类中不能覆盖父类中的该函数,如果尝试覆盖,将会报错
final class 类名{
}
表示该类是最终版本,禁止其他类继承该类。如果尝试继承,则会报错。
3.多态
(1)instanceof
用于确定一个PHP变量是不是属于某一类class的实例,返回bool
$bus = new Bus;
var_dump($bus instanceof Bus);
如果一个对象是一个子类的实例,那么它也是其父类的实例。
(2)如果不用多态,需要大量的流程控制语句。并且假如之后你需要增加一个类class Upan(),那么就需要修改接口test中的代码。
<?php
class Mobile{
function doMobile(){
echo '手机充电';
}
}
class Mouse{
public function doMouse(){
echo '实现mouse的功能';
}
}
class KeyBoard{
public function doKeyBoard(){
echo '实现KeyBoard的功能';
}
}
function test($obj){
if($obj instanceof Mobile){
$obj->doMobile();
}elseif($obj instanceof Mouse){
$obj->doMouse();
}elseif($obj instanceof KeyBoard){
$obj->doKeyBoard();
}else{
echo 'error';
}
}
$apple = new Mobile;
$keyboard = new KeyBoard;
$logic = new Mouse;
test($apple);
test($keyboard);
test($logic);
?>
但是如果改用多态,即便是之后要增加一个类,也不要修改接口test的代码。
<?php
class Device{
public function work(){
echo '这里面内容没用,子类要覆盖';
}
}
class Mobile extends Device{
function work(){
echo '手机充电';
}
}
class Mouse extends Device{
public function work(){
echo '实现mouse的功能';
}
}
class KeyBoard extends Device{
public function work(){
echo '实现KeyBoard的功能';
}
}
function test($obj){
if($obj instanceof Device){
$obj->work();
}else{
echo 'error';
}
}
$apple = new Mobile;
$keyboard = new KeyBoard;
$logic = new Mouse;
test($apple);
test($keyboard);
test($logic);
?>
0X06 常见关键字
1.static
可以修饰成员属性和成员方法
<?php
class A{
public static $a = 'hello world';
public static function test(){
echo 'test';
}
public function run(){
//A::test();//或者写成static::test();或者self::test();
self::test()
echo A::$a;
}
}
echo A::$a;
A::$a = 'xidian'
A::test();
$aaa = new A;
A.run();
?>
对于成员函数在static之后/之前还可以加上public protected等修饰符
静态属性和静态方法不需要类的实例化,就可以直接调用
类名::属性名
类名::方法名()
同时也可以在成员函数中通过上述方式调用静态方法 或者使用 静态属性。
2.self
可以访问本类中的静态属性 和 静态方法 以及 常量,在类中使用,不需要实例化。
self::静态属性
self::静态方法
用self比用类名好,因为如果类名修改了的话,那么类中用类名调用的静态方法、静态属性的语句都需要修改。
建议用self调用静态属性和静态方法,不要用类名也不要用static
self 和 static的区别:
self就是写在哪个类里面,实际调用的就是这个类
static代表使用的这个类,就是你在父类里写的static,然后被子类覆盖,使用的就是子类的方法或属性
<?php
class A{
public static $a='hello world';
public static function test(){
echo "A's test";
}
public function run(){
static::test();
}
}
class B extends A{
public static function test(){
echo "B's test";
}
}
$bbb = new B;
$bbb->run();//B's test
?>
如果将static改为self,将打印A‘s test
3.const
定义常量的两种方式:
常量不需要加$
<?php
define ('PI1',3.14);
const PI2 =3.14;
?>
define 用于在类的外部定义常量,const用于在类的内部定义常量
<?php
class A{
const NAME = 'xidian';
public static function test(){
echo self::NAME;
}
}
echo A::NAME;
?>
访问类中的常量和访问类中的静态变量一样。
类的外部:
类名::常量名
类的内部:
self::常量名(推荐)
static::常量名
类名::常量名
4.parent
如果想要在子类中调用父类的方法,只要:
parent::方法名
5.clone
将对象赋值给对象不能直接使用等号,必须加上clone关键字
class A{
public function test(){
echo 'AAAA';
}
}
$a1 = new A;
$a2 = $a1//error
$a2 = clone $a1;
0x07魔术方法
复习:
八大魔术常量:它们的值会随着它们在代码中的位置的改变而改变
- __LINE__:返回文件中的当前行号,也可以写成__line__
- __FILE__:返回当前文件的绝对路径(包含文件名)
- __DIR__:返回当前文件的绝对路径(不包含文件名),等价于dirname(__FILE__)
- __FUNCTION__:返回当前函数(或方法)的名称
- __CLASS__:返回当前的类名(包括该类的作用区域或命名空间)
- __TRAIT__:返回当前的trait名称(包括trait的作用区域或命名空间)
- __METHOD__:返回当前的方法名(包括类名)
- __NAMESPACE__:返回当前文件的命名空间的名称。
8大魔术方法:
1.__set($name,$val):用于在类的外部给私有变量赋值,相当于重载了给私有变量赋值的等号,当调用给私有变量赋值的等号的时候,实际上调用的是__set($name,$val)函数。
其中私有变量名会赋值给$name ,等号之后的值会赋值给$val;
<?php
class A{
private $a;
private $b;
public function __construct($_a,$_b){
$this->a = $_a;
$this->b = $_b;
}
public function __set($name,$value){
$this->$name = $value;
}
public function __get($name){
return $this->$name;
}
public function show(){
echo $this->a;
echo $this->b;
}
}
$aaa = new A(456,789);
//$aaa->show();
echo $aaa->b;
?>
2.__get($name):凡是在类外需要访问私有变量值的操作,都会自动调用__get()方法
3.__isset() :一般不用
4.__unset():一般不用
5.__call($name,$param):当调用不存在的方法时,会自动调用该方法。
$name = 方法名
$param = 参数 (以数组的形式)
一般在设计框架的时候,经常用该魔术方法。
6.__callstatic($name,$param):当调用不存在的静态方法时,会自动调用该方法。
<?php
class A{
private $a;
private $b;
public function __call($method,$param){
echo $method.'方法不存在';
}
public function static __callstatic($method,$param){
echo '静态方法:'.$method.'不存在';
}
}
$aaa = new A(456,789);
$aaa->test();
A::fuck();
?>
7.__clone() 克隆
当调用clone关键字的时候,会自动调用__clone方法。
相当于:实现克隆功能+实现__clone方法中的代码
<?php
class A{
private $a;
private $b;
public function __clone(){
echo 'hello world';
}
}
$aaa = new A(456,789);
$bbb = clone $aaa;
echo '<br/>';
var_dump($bbb);
echo '<br/>';
var_dump($aaa);
?>
注意:以上代码克隆功能并没有失效。
8.__toString
当在外部echo 对象时自动调用该方法。
<?php
class A{
private $a;
private $b;
public function __toString(){
return 'hello world';
}
}
$aaa = new A(456,789);
echo $aaa;
?>
9.序列化与反序列化
如果直接echo数组,那么只会输出array。
如果偏要echo出数组,就必须先将数组序列化后,再echo
<?php
$arr = ['welcome','to','xidian'];
$after = serialize($arr);
echo $after;
//a:3:{i:0;s:7:"welcome";i:1;s:2:"to";i:2;s:6:"xidian";}
$before = unserialize($before);
print_r($before);
?>
a表示array,3表示数组的长度
序列化之后的数据可以直接存到数据库中。同样也可以从数据库中抽出来,通过反序列化,还原为原来的形式
对于 类 ,我们可以在 __toString()方法中将类序列化,这样类也能echo了
<?php
class A{
private $a;
private $b;
public function __toString(){
return serialize($this);
}
}
$aaa = new A(456,789);
echo $aaa;
?>
0x08 抽象类
抽象方法:没有函数体的方法。用abstract修饰
含有抽象方法的类就是抽象类。用abstract修饰.
抽象类不能被实例化。抽象类是用来被继承的。天生就是用来当爹的。
而抽象方法是用来被重载的。在子类中需要重载抽象方法。
<?php
abstract class A{
public $name = 'xidian';
public abstract function test();
public function run(){
echo 'hello world';
}
}
class B extends A{
public function test(){
echo 'hello xidian';
}
}
$b = new B;
$b->run();
$b->test();
?>