欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

分级命名空间与trait类学习

程序员文章站 2022-03-11 13:42:22
...

1. 分级命名空间

php 中命名空间是可以定义成类似目录路径的形式,如( Mi\You\Him )

当我们在一个命名空间下需要访问另一空间下的成员时,比如说类,便需要在 类前加上对应的命名空间,这就会形成比较繁琐的代码书写。

因此,可以使用 use 关键字来简化类名。

先声明几个名空间:space.php

<?php
namespace day1010\One;

class Test1
{
    public static function demo()
    {
        return __METHOD__;
    }
}

namespace day1010\One\Two;

class Test1
{
    public static function demo()
    {
        return __METHOD__;
    }
}

使用 use 来引用需要的类:

<?php

namespace day1010;

include __DIR__.'/spaces.php';

// use
// 默认从全局开始, 可以省略掉: \
// as 给当前的空间名称起一个别名
// 防止当前空间名称命名冲突

use day1010\One\Test1; // // 如果省略as ,那么当前类的别名就是当前类的去掉空间名称的类名
use day1010\One\Two\Test1 as T;

echo Test1::demo(); // day1010\One\Test1::demo
echo '<hr>';
echo T::demo(); // day1010\One\Two\Test1::demo
echo '<hr>';
echo namespace\One\Test1::demo();

PS:  namespace 关键字 和 __NAMESPACE__常量区别

1. 常量__NAMESPACE__的值是包含当前命名空间名称的字符串,这个应该很好理解。

2. 关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素。它等价于类中的 self 操作符。

    可以将 namespace看成是当前命名空间的一个引用,在使用一个类时,我们可以这样写。 

2. trait

php 只能实现单继承,无法同时从两个基类中继承属性和方法,为了解决这个问题,php实现了一种代码复用的方法,称为 trait。

trait 可以实现让一个类从 多个 trait类中进行继承,实现类似多继承的机制。

1.  trait是一种代码复用的手段

2.  trait 使用的是类的语法,不过它不是类,不能被实例化


<?php

namespace day1010;

use PDO;

trait DB
{
    public function connect($dsn, $username, $password)
    {
        return new PDO($dsn, $username, $password);
    }

    public function test()
    {
        return '这是 DB 中的 test()';
    }
}

// 查询父类
class Query
{
    public function get(PDO $pdo, $where = '')
    {
        $where = empty($where) ? '' : ' WHERE ' . $where;
        $sql = 'SELECT * FROM `staff`' . $where . ' LIMIT 5';
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function test()
    {
        return '这是 Query 中的 test()';
    }
}

// 定义一个 trait类
trait Query_user
{
    // 这里也定义一个 查询方法,不过改为默认查询 1条
    public function get(PDO $pdo, $where = '')
    {
        $where = empty($where) ? '' : ' WHERE ' . $where;
        $sql = 'SELECT * FROM `staff`' . $where . ' LIMIT 1';
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function test()
    {
        return '这是 Query_user 中的 test()';
    }
}

class Client extends Query
{
    当引用 不同trait时出现重名方法时,可以这样来区分 
    use DB, Query_user {
        DB::test insteadof Query_user; // 这里表示用 DB 中的 test方法代替 Query_user中的
        Query_user::test as q_test; // 可以将 Query_user 中 test 改名来进行使用
    }

    public $pdo = null;

    public function __construct($dsn, $username, $password)
    {
        // 这里就可以访问 DB 中的 connect方法
        $this->pdo = $this->connect($dsn, $username, $password);
    }

    public function select($where)
    {
        // 这里是 访问的 父类中的 get(),还是 trait中的get()呢?
        return $this->get($this->pdo, $where);
    }

    // public function getClassName() {
        // return $this->test();
        // return $this->q_test();
    // }


}

$client = new Client('mysql:dbname=zmx', 'root', 'root');
// 结果显示,调用的是 trait中的方法,因此,可以得知 trait 是夹在父类与子类之间的,trait会覆盖父类方法
echo '<pre>' . print_r($client->select('staff_id >3'), true);

echo $client->q_test();

总结:

1. trait 优先级比父类高,会覆盖父类中的成员方法

2. 一个类中可以继承多个 trait