Skip to content

PHP 类和对象 #68

@huliuqing

Description

@huliuqing

面向对象编程

目录

一 属性和 static (静态)关键词

1.1 属性

OOP 属性文档

类的成员变量叫属性(也称为:特性或字段)

1.1.1 属性声明

访问控制(public, protected, private)开头,紧跟普通变量声明

1.1.2 属性初始化

属性值必须为常数,不能为表达式或需要计算运行的结果

1.1.3 访问方式

  • 静态属性(static 修饰的属性),使用范围解析运算符(::)访问
  • 非静态属性,使用对象运算符(->)访问

1.2 static (静态)关键词

OOP static (静态)关键词文档

1.2.1 功能

1.2.2 示例

<?php
class Foo
{
    //定义类的静态属性
    public static $foo = "foo";

    //定义类的静态方法
    public static function who()
    {        
    }
}
<?php
function add()
{
    // 定义静态变量
    static $counter = 0;

    ++$counter;

    return $counter;
}

1.2.3 使用静态属性或方法

  • ① 类的静态属性或方法,可以不实例化直接访问(Foo::bar(), Foo::$bar)
  • ② 类实例对象可值通过对象运算符(->)访问静态方法,但不能访问静态属性(✔ $foo->bar(), ✖ $foo->$bar)
  • ③ $this (伪变量)在静态方法中不可用
  • ④ 静态方法不能访问非静态方法
  • ⑤ 静态属性初始化值规则同「1.1.2 属性初始化」

1.3 后期静态绑定(延迟静态绑定)

OOP 后期静态绑定文档

1.3.1 作用

在调用静态方法时获取实际调用类或对象,而非定义该方法的类(如: Base 父类,和 A 子类,皆定义 get() 方法(或静态方法);实际调用类是 A,则实际对象为 A)

1.3.2 后期静态绑定原理

  • 静态方法调用,解析的运行时类为范围解析运算符(::)左侧的类名
  • 非静态方法调用,则为调用方法的实例对象
<?php

class Base
{
    public function who()
    {
        var_dump(__CLASS__);
    }

    public static function t()
    {
        static::who();
    }

    public function t1()
    {
        // @link self:: 的限制 http://php.net/manual/zh/language.oop5.late-static-bindings.php
        self::who();
    }

    public function t2()
    {
        static::who();
    }
}

class A extends Base
{
    public function who()
    {
        var_dump(__CLASS__);
    }
}

class B extends Base
{
    public function who()
    {
        var_dump(__CLASS__);
    }
}

// 后期静态绑定,调用静态方法
A::t(); // A
B::t(); // B

$a = new A();
$b = new B();

// 后期静态绑定,实例对象调用非静态方法
$a->t2();// A
$b->t2();// B

// 非后期静态绑定
$a->t1();// Base
$b->t1();// Base

1.4 类型约束

PHP 类型约束文档

1.4.1 概念

定义函数或方法是,对参数进行类型限定

1.4.2 支持的类型约束类型

1.4.3 不支持的类型约束类型

  • int
  • string
  • float
  • bool
  • traits

1.5 一个比较完整但无意义的示例

<?php

function dump($data)
{
    echo "<pre>";
    var_dump($data);
    echo "</pre>";
}

class Foo
{
    public $commProp = "commProp";

    public static $staticProp = "staticProp";

    public function commMethodCallStaticMethod()
    {        
        dump("-- start :in commMethodCallStaticMethod--");
        dump($this->commProp);

        dump("-- start :call staticMethod--");
        $this->staticMethod();
    }

    public function commMethod()
    {
        dump("-- start: \$this->commProp--");
        dump($this->commProp);
    }

    public static function staticMethodCallCommMethod()
    {
        dump("-- start --");
        $this->commMethod();
    }

    public static function staticMethod()
    {
        dump("-- start: self::\$staticProp --");
        dump(self::$staticProp);
    }

    public function delayStaticBindMothod()
    {
        dump("-- start: static::\$staticProp --");
        dump(static::$staticProp);
    }
}

class Bar extends Foo
{
    public static $staticProp = 'childStaticProp';
}

dump('--dump: Foo::$staticProp');
dump(Foo::$staticProp);
dump('--dump: end');
echo "<br/>";

dump('--dump: Foo::staticMethod()');
Foo::staticMethod();
dump('--dump: end');
echo "<br/>";

dump('--dump: Bar::staticMethod()');
Bar::staticMethod();
dump('--dump: end');
echo "<br/>";


dump('--dump: Foo::delayStaticBindMothod()');
Foo::delayStaticBindMothod();
dump('--dump: end');
echo "<br/>";

dump('--dump: Bar::delayStaticBindMothod()');
Bar::delayStaticBindMothod();
dump('--dump: end');
echo "<br/>";

$foo = new Foo();

dump('--dump: install Foo class $foo->commMethodCallStaticMethod()');
$foo->commMethodCallStaticMethod();
dump('--dump: end');
echo "<br/>";

dump('--dump: install Foo class $foo->staticProp');
dump($foo->staticProp);
dump('--dump: end');
echo "<br/>";

dump('--dump: Foo::staticMethodCallCommMethod()');
Foo::staticMethodCallCommMethod();
dump('--dump: end');
echo "<br/>";

二 对象继承与抽象类

::class : 类名解析,使用 ClassName::class 你可以获取一个字符串,包含了类 ClassName 的完全限定名称。这对使用了 命名空间 的类尤其有用。

PHP 对象继承文档
PHP 抽象类文档

2.1 对象继承

  • 子类将继承父类所有公有(public)和受保护(protected)的方法
  • 父类(普通类,抽象类或接口)必须在子类之前定义

2.2 抽象类特性

  • 如果类中定义一个及以上抽象方法(abstract public function),则类必须声明为抽象类(abstract class)
  • 抽象类不能实例化
  • 抽象类只能声明调用方式(及参数),不能定义实现(函数体)

2.3 抽象类继承特性

  • 继承类(子类)必须实现抽象类所有抽象方法
  • 继承类(子类)实现方法的访问控制(public, protected, private),必须等于或高于抽象类方法
  • 继承类(子类)对抽象方法的实现,在参数类型及个数上必须与父类保持一致;
    但如果实现方法自定义抽象类中没有的可选参数,则声明不冲突

2.4 示例

<?php

abstract class Weapon
{
    
    abstract public function fireTo();

    abstract protected function shoot();
}

class Gun extends Weapon
{
    
    public function fireTo($target = 'enemy')
    {
        printf("Fire to : %s. %s", $target, PHP_EOL);
    }

    public function shoot()
    {
        echo "I'm shoot.";
    }
}

$gun = new Gun();

$gun->fireTo();
$gun->shoot();

三 对象接口

PHP 对象接口文档

3.1 定义

  • 关键字 interface 定义接口
  • 同抽象类一样,仅声明调用方式(及参数),不能定义实现(函数体)
  • 接口中所有方法必须公有(public)
  • 接口中可定义常量,实现类不能覆写接口中常量

3.2 实现

  • 实现类实现接口使用 implements 操作符
  • 可实现多个接口
  • 实现多个接口时,接口中方法不能有重名方法
  • 实现类对接口方法的实现,在参数类型及个数上必须与接口保持一致;
    但如果实现方法自定义接口中没有的可选参数,则声明不冲突

3.3 示例

该示例实现了对 2.4 示例的扩展

<?php

/**
 * 射击瞄准镜
 */
interface GunSight
{
    const MAX_AIM_DISTANCE = 3000;

    /**
     * [aimAt 瞄准功能]
     */
    public function aimAt();
}

/**
 * 无限弹药
 */
interface UnlimitedAmmo
{
    public function ammo();
}

abstract class Weapon
{
    
    abstract public function fireTo();

    abstract protected function shoot();
}

class Gun extends Weapon implements GunSight, UnlimitedAmmo
{
    /**
     * [fireTo description]
     * 
     * @inherit
     * 
     * @param  string $target [description]
     */
    public function fireTo($target = 'enemy')
    {
        printf("Use gun fire to %s. %s", $target, PHP_EOL);
    }

    /**
     * [shoot]
     * 
     * @inherit
     */
    public function shoot()
    {
        printf("now is shooting.%s", PHP_EOL);
    }

    /**
     * [aimAt ]
     * 
     * @implements
     * 
     * @param  string $target [description]
     */
    public function aimAt($target = 'enemy')
    {
        printf("Now gun has gun sight,can aim at %s,the max distance is %s m.%s", $target, self::MAX_AIM_DISTANCE, PHP_EOL);
    }

    /**
     * [ammo]
     * 
     * @implements
     */
    public function ammo()
    {
        printf('Unlimited ammo support. %s', PHP_EOL);
    }
}

$gun = new Gun();

$gun->ammo();
$gun->aimAt();
$gun->fireTo();
$gun->shoot();

三 重载

PHP 重载文档

3.1 PHP 重载的概念

** PHP 重载 **
对象调用类未定义或不可见(private)的类属性或方法时,重载方法会被调用

** 其它语言重载定义 **

TODO

3.2 重载方法

3.2.1 属性重载的魔术方法

  • __get($name, $value): 给不可访问属性或未定义属性赋值时被调用
  • __set($name): 读取不可访问属性或未定义属性时被调用
  • __isset($name): 当不可访问属性或未定义属性调用 isset() 或 empty() 时,被调用
  • __unset($name): 当不可访问属性或未定义属性调用 unset() 时,被调用

3.2.2 方法重载的魔术方法

  • __call($name, array $arguments): 当对象调用不可访问方法时,被调用
  • __callStatic($name, array $arguments): 在静态上下文中调用不可访问方法,被调用

3.3 注意事项

  • 重载魔术方法必须声明为 public
  • 参数不能为应用传递

四 魔术方法

PHP 魔术方法文档

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions