PHP类详解二

PHP类和接口的继承都使用extends关键字,PHP类只能继承一个父类(单继承),但是接口和类不同,接口可以实现多继承,可以继承一个或者多个接口。接口要多个继承的话只要用逗号把继承的接口隔开即可。

类的继承

PHP中子类可以继承父类所有的属性和方法,子类可以拓展自己的属性和方法,也可以重写父类的属性和方法。重写时5.2以前参数可以不同(因为PHP没有重载),5.3以后参数个数必须一致,且访问级别必须大于等于父类的方法。final 修饰的方法不可重载。

class Site
{
    var $category="父亲";

    function display(){

        echo $this->category;
    }
}

// 子类扩展站点类别
class Child_Site extends Site {
    var $category="儿子";

    function setCate($par){
        $this->category = $par;
    }
}
$oneFather=new Site();
$oneFather->display();
$oneChild=new Child_Site();
$oneChild->display();

结果:

父亲儿子

如果子类没有category属性和话会继承父类的category属性,结果就会是父亲父亲

子类调用父类构造方法

PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。

<?php
class BaseClass {
    function __construct() {
        print "BaseClass 类中构造方法" . PHP_EOL;
    }
}
class SubClass extends BaseClass {
    function __construct() {
        parent::__construct();  // 子类构造方法不能自动调用父类的构造方法
        print "SubClass 类中构造方法" . PHP_EOL;
    }
}
class OtherSubClass extends BaseClass {
    // 继承 BaseClass 的构造方法
}
// 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();

// 调用 BaseClass 构造方法
$obj = new OtherSubClass();
?>

结果

BaseClass 类中构造方法
SubClass 类中构造方法
BaseClass 类中构造方法

访问控制

PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。

  • public(公有):公有的类成员可以在任何地方被访问。
  • protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
  • private(私有):私有的类成员则只能被其定义所在的类访问。

对属性的访问控制

类的属性必须被定义为公有,受保护和私有之一。如果变量前面没有var 和访问控制符的话会报错,用var定义默认是public的。

<?php
//PHP_EOL="\n";
class MyClass
{
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    function printHello()
    {
        echo $this->public.PHP_EOL;
        echo $this->protected.PHP_EOL;
        echo $this->private.PHP_EOL;
    }
}

$obj = new MyClass();
echo $obj->public.PHP_EOL; // 这行能被正常执行
#echo $obj->protected; // 这行会产生一个致命错误
#echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // 可以对 public 和 protected 进行重定义,但 private 而不能
    protected $protected = 'Protected2';

    function printHello()
    {
        echo $this->public.PHP_EOL;
        echo $this->protected.PHP_EOL;
       # echo $this->private;//不能继承私有属性
    }
}

$obj2 = new MyClass2();
echo $obj2->public.PHP_EOL; // 这行能被正常执行
#echo $obj2->private; // 未定义 private
#echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>

结果:

Public
Public
Protected
Private
Public
Public
Protected2

从以上代码中可以看出,只有公有属性能被对象直接访问,私有属性和受保护属性必须调用方法来使用。继承不能继承父类的私有属性。

方法的访问控制

类的方法默认为公有,类中的方法可以被定义为公有,私有或受保护。

<?php
//PHP_EOL="\n";
class MyClass
{
    // 声明一个公有的构造函数
    public function __construct() { }

    // 声明一个公有的方法
    public function MyPublic() { }

    // 声明一个受保护的方法
    protected function MyProtected() { }

    // 声明一个私有的方法
    private function MyPrivate() { }

    // 此方法为公有
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
#$myclass->MyProtected(); // 这行会产生一个致命错误
#$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行


class MyClass2 extends MyClass
{
    // 此方法为公有
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        #$this->MyPrivate(); // 这行会产生一个致命错误
    }
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行
?>

从以上代码可以看出,私有方法不可继承,对象只能调用公有方法,受保护的和私有的方法只能通过公有方法间接调用。

接口

接口是类行为的抽象,指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

接口中定义的所有方法都必须是公有,这是接口的特性。

接口中只能定义常量(不能静态常量),子类不能重写常量,只能通过 interfaceName::YOUCONST的方式调用,不能通过parent::YOUCONST的方式调用接口的常量。

但是在类中可以定义静态成员变量,子类能重写常量,const 变量可以使用parent::YOUCONST的方式,className::YOUCONST的方式在子类中访问。

<?php

// 声明一个'iTemplate'接口
interface iTemplate
{
     const TEST="444";
    public function getVariable();
}


// 实现接口
class Template implements iTemplate
{

    private $vars = array();

    public function getVariable()
    {
       echo iTemplate::TEST;
    }
}
$dd=new Template();
$dd->getVariable();

抽象类

任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。

定义为抽象的类不能被实例化。

被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。

抽象类可以定义变量和静态变量以及常量,因为抽象类是对类属性和行为的抽象。

<?php
abstract class AbstractClass
{
    var $test=55;
    // 强制要求子类定义这些方法
    abstract protected function getValue();
    // 普通方法(非抽象方法)
    public function printOut() {
        echo $this->getValue().PHP_EOL,$this->test , PHP_EOL;
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

}

$class1 = new ConcreteClass1;
$class1->printOut();

$class2 = new ConcreteClass2;
$class2->printOut();
?>

结果:

ConcreteClass1
55
ConcreteClass2
55

static关键字

声明类属性或方法为 static(静态),就可以不实例化类而直接访问。

静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。

由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。

静态属性不可以由对象通过 -> 操作符来访问。

自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。

<?php
class Foo {
    public static $my_static = 'foo';

     static function staticValue() {
        return self::$my_static;
    }
}

print Foo::$my_static . PHP_EOL;
$foo = new Foo();
echo $foo->my_static."对象无妨访问静态属性".PHP_EOL;
echo '类名访问静态方法',Foo::staticValue().PHP_EOL;
print "对象访问静态方法".$foo->staticValue() . PHP_EOL;
?>

结果:

foo
对象无妨访问静态属性
类名访问静态方法foo
对象访问静态方法foo

Final 关键字

PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注