zoukankan      html  css  js  c++  java
  • PHP类的变量与成员,及其继承、访问与重写要注意的问题

    PHP的类及其实例:

    <?php
    class Myclass{
    public $prop = 123;
    }
    $obj = new Myclass();
    ?> 

    类的成员属性(属性的称呼相对于‘方法’而言)包括类常量和类变量,其中类常量在定义时不可为空,类的属性在定义时如果被赋值,只能使用变量和数组,并且不能是表达式,因为类属性在编译期被初始化,PHP在编译器不执行表达式。

    1、成员的访问控制

    public:可以继承,可以在类的方法之外被访问,如$obj->prop;

    protected:可以继承,不可以在类的方法之外被访问;

    private:不可以继承,不可以在类的方法之外访问;

    PHP4使用var来声明类的属性,在PHP5之后不再使用,PHP5.3之前使用被警告,在PHP5.3之后可以在public之前或单独使用作为public的别名。

    这三个访问控制关键字也可以修饰构造函数,当private和protected修饰类的构造函数时,只能通过一个public static的静态方法调用构造函数以实例化对象,因为该构造函数无法在类之外被访问了,比如,单例类的实现:

    <?php
    class Singleton{
    private static $instance = null;
    public $k = 88;
    private function __construct(){
    }
    public static function getInstance(){
    if(self::$instance == null){
    //self::$instance = new Singleton();
    self::$instance = new self();
    }
    return self::$instance;
    }
    public function __clone(){
    throw new Exception('Singleton class can not be cloned');
    return self::$instance;
    }
    }
    //$in = new Singleton();
    $in = Singleton::getInstance();
    var_dump($in);
    ?> 

    2、继承禁止:final关键字,仅用于修饰类或类的方法

    如果一个类被final修饰,这个类不能被继承,如果一个方法被final修饰,则这个方法不能被子类重写(override)。

    <?php
    class Myclass{
    public $prop = 123;
    final public static function methodA(){
    return 'this is a final method';
    }
    }
    ?> 

    3、抽象类和抽象方法,abstract仅用于类和方法,抽象类不能直接用于实例化对象,只能用于产生子类

    <?php
    abstract class Myclass{
    public $prop = 123;
    abstract public function methodA();//抽象方法没有实现函数体
    }
    ?> 

    4、类的常量及其访问:类的常量不能使用访问控制修饰符,他是public的,可继承,可以被子类重写。访问类的常量必须使用双冒号::可以使用类名或类的实例(对象)来访问,因为是常量,所以名称不能使用表示变量的符号$。

    <?php
    class Myclass{
    public $prop = 123;
    const X = 999;
    final public static function methodA(){
    return 'this is a final method';
    }
    public function getConst(){
    return self::X;//或者$this::X
    }
    }
    $in = new Myclass();
    echo $in->getConst();
    echo Myclass::X;
    ?> 

    类的常量是一个值,在代码编译器常量名被替换为相应的值,在运行期不可修改,因此类的常量与类本身无关,在类实例化对象之前就已经存在,因此类的常量可以直接使用类名访问

    <?php
    class P{
    const M = 100;
    const N = self::M;
    public static $k = 99;
    public function getStatic(){
    return self::$k;
    }
    public function getStatic2(){
    return static::$k;
    }
    }
    class S extends P{
    const M = 200;
    public static $k = 88;
    public function getPConst(){
    return parent::N;
    }
    }
    $p = new P();
    $s = new S();
    echo $p::N.'<br>';//100
    echo $s::N.'<br>';//200 该常量名继承自父类,在编译期就已经直接取 self::M 的值替换了 ,注意区别类的方法中使用 self::M
    echo $s->getPConst().'<br>';//100
    echo $s->getStatic2().'<br>';//88
    ?> 

    5、类的静态成员访问

    static可以修饰类的属性和方法,被static修饰的成员归属于类而非类的实例。静态成员必须使用类名加双冒号::来访问,因此在实例化对象之前静态成员就存在了,因此,在静态方法内禁止使用指向实例本身的伪变量$this(或习惯上称为$this指针),可以使用关键字self代替类名(相当于类的魔术常量__CLASS__)。

    static不能修饰类的构造函数,也不能修饰接口声明的方法。

    <?php
    class Myclass{
    public static $x = 99;
    public function getX(){
    return self::$x;
    }
    public static function getX2(){
    return self::$x;
    }
    }
    echo Myclass::$x."<br>";
    echo Myclass::getX2()."<br>";
    $MC = new Myclass();
    echo $MC->getX2()."<br>";
    ?> 

    静态成员可以使用访问控制关键字修饰,可以被继承和重写,需要注意的是,如果一个子类继承了父类的静态方法(没有重写该方法),那么子类调用的实际是父类的静态方法。因为静态成员持有者是类不是对象,所以类的多个实例是共享一个静态属性,在一个实例中修改静态属性会影响到另一个实例的静态属性:

    <?php
    class A{
    public static $a1 = 11;
    public $a2 = 22;
    public static function showStatic(){
    return self::$a1;
    }
    public function getStatic(){
    return self::$a1;
    }
    public function getClassStatic(){
    $className = get_called_class();
    return $className::$a1;
    }
    public function getProp(){
    return $this->a2;
    }
    }
     
    class B extends A{
    public static $a1 = 88;
    public $a2 = 99;
    }
     
    $obj1 = new A();
    $obj2 = new B();
     
    echo $obj1->getStatic()."<br>";//11
    echo $obj1->getClassStatic()."<br>";//11
    echo $obj1->getProp()."<br>";//22
     
    echo B::showStatic()."<br>";//11调用的是父类的方法,访问父类的静态成员
    echo $obj2->getStatic()."<br>";//调用的是父类的方法,方法中的slef指向持有该静态方法的类
    echo $obj2->getClassStatic()."<br>";//88
    echo $obj2->getProp()."<br>";//99
    ?> 

    后期静态绑定:为了避免子类重写静态属性后,使用继承来的方法仍然方法父类的静态属性,PHP5.3增加了一个新的语法,后期静态绑定,使用static关键词替代self关键字,使得static指向与get_called_class()返回的相同类,即当前调用该静态方法的对象所属的类,该关键字对于静态方法的访问同样有效。

    public function getClassStatic(){

    $className = get_called_class();

    return $className::$a1;

    }

    //可以写成

    public function getClassStatic(){

    return static::$a1;

    }

    6、类的方法中几个指向类或实例的关键字

    $this->propName    $this指向类的实例

    parent::xxx      parent指向父类,可以访问父类的静态常量、静态属性,不能访问父类的非静态属性可以调用父类的方法(不能是private方法,无论是否静态)

    self::xxx   self指向定义了当前被调用的方法的类,用于访问静态成员和类的常量

    static::xxx  访问实例化了调用当前方法的实例的那个类,用于访问静态成员和类的常量,它跟self的差别是访问静态成员是“后期静态绑定”

    7、类的继承中的重写问题

    重写的成员的访问控制程度不能被缩小,例如,public的成员不能重写为protected

    非静态成员不能重写为静态成员,静态成员也不能重写为非静态成员

    8、接口中定义的方法必须是public

    类在实现接口的方法时,这些方法也必须是public的。

    接口也可以定义接口常量,用法和类的常量一致,但是接口不可以定义非函数成员。

    接口与接口之间可以继承,接口的继承可以是多继承,用逗号隔开(子类与父类的继承是单继承)。

    一个口可以实现多个接口,用逗号隔开。

    <?php
    interface Ix extends Iy,Iz{
       public function a();
    }
     
     
    class A implements Iy,Iz{
     
       //.......
     
    }
    ?> 

    9、类型约束

    PHP的函数(或类的方法)可以在声明是限定参数的类型,但只能限定array或object(class/interface),如果限定为string,PHP会认为是限定为一个string类的object参数。

    如果类型被限定为某一个接口,则传入的参数必须是实现该接口的类的实例。

    在接口实现、子类重写父类方法时,不能修改已经限定的参数类型。

    在方法、函数调用时,如果传入了与限定的参数类型不同的数据将会报错,但是可以接收null参数。

    <?php
    interface Im{
       public function a( classm $m);
    }
     
     
     
    class A implements Im{
        public function a($x){   // error ,参数$x必须限定为 classm 类型以匹配接口的定义
           var_dump($x);
        }
    }
    ?> 
  • 相关阅读:
    RabbitMQ资料
    在网页打开本地程序的思路
    HttpClient的巨坑
    webbrowser设置为相应的IE版本
    cpupower:Shows and sets processor power related values
    golang 国内环境配置
    OSX 创建 randisk(或称 tmpfs)
    Gentoo 搭遗
    ubuntu 去除开机背景
    fabric && cita 调研对比
  • 原文地址:https://www.cnblogs.com/zhouguowei/p/5209728.html
Copyright © 2011-2022 走看看