- 2019-11-17
PHP基础加强系列八之OOP相关内容(三...
序言:这篇文章主要讲了OOP相关知识,例如:抽象类,接口,final关键字,对象序列化,类常量,trait,对象遍历等
(1).PHP抽象类
当一个类含有不确定的方法时,将这个方法声明为抽象方法,而含有一个抽象方法的类必须声明为抽象类;抽象类主要是用在设计,让其他类来继承它,实现它里面的方法;
细节:
1.抽象类不能被实例化;抽象方法没有方法体;
abstract class Food{
abstract public function cry();
}
$food = new Food(); //不能实例化抽象类
2.抽象类可以没有抽象方法
abstract class Food{
public name;
public function cry(){
echo 'haha';
}
}
3.一个类继承了一个抽象类,则必须实现抽象类里的所有抽象方法;如果继承类不想重写抽象类的抽象方法,可以将继承类声明为抽象方法;
abstract class Food{
abstract function cry();
public function run()
{
return '动物跑';
}
}
class Fish extends Food {
public function cry()
{
return '哈哈';
}
}
//必须重写抽象类的cry方法,run方法可以不重写;
abstract class Bone extends Food {
}
//这个时候,虽然继承了抽象方法food,但是声明了抽象,所以不用重写food的抽象方法;
4.抽象类可以有普通属性和常量;
(2).php接口
使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
接口中定义的所有方法都必须是公有,这是接口的特性。
细节:
1.命名规范,以i开头,后跟驼峰法命名
interface iMyInterface{
public function cry();
}
2.接口不能被实例化
3.接口多继承,多个接口使用,分割;继承多个接口的类,必须实现所有接口的所有方法;
interface A{
public function cry();
}
interface B{
public function run();
}
class C implements A,B{
public function cry()
{
return 'cry';
}
public function run()
{
return 'run';
}
}
4.接口里可以有普通属性,但只能是常量;不能是普通变量;
interface A{ const MAX = 0.2; public name;
public function cry();
}
//Fatal error: Interfaces may not include member variables
//接口里不能有普通变量,可以有常量;
5.一个接口不能继承其它类,但是可以同时继承多个接口;
interface A{
public function cry();
}
interface B{
public function run();
}
interface C extends A,B{ //接口C多继承了A和B
public function talk();
}
class D implements C{ //类D继承了接口C,所以要实现全部方法
public function cry()
{
}
public function run()
{
}
public function talk()
{
}
}
(3).PHP关键字之final
1.final不能修饰成员属性;
//例如这样: final public name;
2.final修饰的类不能被继承;
final class A{} class B extends A{} //报错
3.final修饰的成员方法不能被重写
class A{ final public function cry(){ echo 'cry'; } } class B extends A{ public function cry(){ echo 'talk'; } //报错,不能重写父类的final修饰的成员方法; }
4.final类是可以被实例化的;
final class A{} a = new A(); //不会报错
(4).类常量
类常量类型可以是(int/float/string/null/bool/array),不能是object;类常量不能有访问修饰符,常量值不能在其他地方修改;定义常量必须初始化;
final class A{
const MAX = array('num1'=>0.08,'num2'=>0.09);
}
echo A::MAX['num1']*1000;
A::MAX['num1'] = 0.5; //报错,不能修改常量值;
或者:
a = new A(); echo a::MAX['num2'];
//类常量是一个全局范围,可以在任何一个函数中使用;
final class A{
const MAX = array('num1'=>0.08,'num2'=>0.09);
}
class B{
public function cc()
{
return A::MAX['num2'];
}
}
b = new B(); echo b->cc();
(5).对象遍历
对象遍历通过foreach来遍历,用法同数组遍历一样;但是在类外遍历只能遍历类的共有属性;
final class A{
public name = '123'; protected age = 12;
private height = 1.85; } a = new A();
foreach (a as k => v) { echo '
'.k.'=>'.v; } 输出: name=>123
//要想遍历全部属性,可以在类中遍历
final class A{ public name = '123';
protected age = 12; private height = 1.85;
public function cc()
{
foreach (this as k =>v) { echo '
'.k.'=>'.v; } } } a = new A();
a->cc(); 输出: name=>123 age=>12 height=>1.85
(6).PHP反射类
通过反射类来直接输出类的相关属性和方法,当你要直接输出一个对象时,可以用到反射类,它能帮助你输出类的所有信息;
class A{ public name = '123';
protected age = 12; private height = 1.85;
public function __toString()
{
reflection = new ReflectionClass(this);
method = reflection->getMethods();
properties = reflection->getProperties();
var_dump(properties[0]->getValue(this));
return '';
}
}
a = new A(); echo a;
(7).对象序列化
所谓对象序列化就是将一个对象的属性名称,属性类型,和属性的值都保存到文件中,可以通过反序列化把对象重新恢复;
当需要把对象写入文件或者写入session中就要用到对象序列化;
小例子:序列化一个对象,在test.php中
class Student{
public name; protected age;
private school; public function __construct(name,school)
{
this->name = name;
this->age = age;
this->school =school;
}
}
class School{
public name; public address;
function __construct(address)
{
this->name = name;
this->address = address;
}
}
school = new School('成都东软学院','四川省成都市都江堰市'); student = new Student('王二狗',23,school); file_put_contents(__DIR__.'\cs.txt',serialize(student));
//此时就会在当前目录下创建一个cs.txt文件,并将对象写入文件;
//在test2.php中反序列化对象,得到该对象的所有信息
require './…/test.php';
student = unserialize(file_get_contents('./../cs.txt')); var_dump(student);
//此时能获取到保存到文件中的对象内容,但是前提是先引入先前定义好的类;或者将先前定义的类再写一遍
class Student{
public name; protected age;
private school; public function __construct(name,school)
{
this->name = name;
this->age = age;
this->school =school;
}
}
class School{
public name; public address;
function __construct(address)
{
this->name = name;
this->address = address;
}
}
student = unserialize(file_get_contents('./../cs.txt')); var_dump(student);
(8).PHP面向对象编程之trait
为了解决PHP单继承有时候的限制,同时为了提高代码复用性,引入trait
小例子:这里有一个基类A,它有一个方法cry(),它有三个子类,B,C,D,现在有一个需求就是要求B和C这两个子类再添加一个相同的方法run();而D类不添加,你会怎么实现?你可能会自己在B和C类手动再添加一个方法run();但是这样不利于提高代码复用性,同时增加了维护开销,如果不止添加一个方法呢,你就要重复很多动作;为了解决这个问题,我们可以定义一个trait类E,在E中写入run()方法,然后再B和C中去引入E就行了;
代码如下:
class A{
public function cry()
{
return 'A';
}
}
class B extends A{
use E;
public function showMethod()
{
return this->run().' '.this->cry();
}
}
class C extends A{
use E;
}
class D extends A{
}
trait E{
public function run()
{
return 'E';
}
}
b = new B(); echo b->showMethod();
输出:
E A
//在其它类引入trait用use+类名就行;
//注意细节:
1.trait定义的类不能被实例化.
e = new E(); //报错:Cannot instantiate trait E
2.如果父类和trait类有相同方法,优先使用trait类的方法
class A{ public function cry() { return 'A'; } public function walk() { return 'A-walk'; } } trait E{ public function run() { return 'E'; } public function walk() { return 'E-walk'; } } b = new B();
echo $b->walk();
输出:
E-walk
转载请注明出处,谢谢!你的意见是对我最大的帮助。
评论一下