Skip to content

PHP 类和对象 #68

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 魔术方法文档

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions