PHP基础加强系列八之OOP相关内容(三...

胡三金 2017-06-21 11:24:02 3252 0 comments

序言:这篇文章主要讲了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,age,age,school)
    {
        this->name =  name;
        this->age = age;
        this->school =school;
    }
}
class School{
    public name;     public address;
    function __construct(name,name,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,age,age,school)
    {
        this->name =  name;
        this->age = age;
        this->school =school;
    }
}
class School{
    public name;     public address;
    function __construct(name,name,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


转载请注明出处,谢谢!你的意见是对我最大的帮助。



标签
评论一下

评论列表

暂时没有评论,快来评论吧..