资讯专栏INFORMATION COLUMN

Laravel 中的一个后期静态绑定

30e8336b8229 / 2564人阅读

摘要:实验一个抽象类,有个方法,通过延迟静态绑定实例化并返回。这里如果把注释打开,打印的就是重写的值如果把抽象类改成普通类,改成的方式实例化,结果就不同了,打印的属性都是各自类的属性。

(原文地址,内容以原文为准,可能修改或者补充:https://blog.tanteng.me/2017/...)

关于 PHP 的 new static 延迟静态绑定,或者叫后期静态绑定,在 Laravel 中遇到一个使用上的问题。如下,在 Laravel 中调用 Model 新增数据的时候,首先给 Model 加了一个获取分表的方法:

protected function addToMessage($msgType, $userID, $commentID, $replyCommentID, $replyUserID, $gameID)
{
    if (!$userID) {
        return false;
    }
 
    $table = "t_message_" . hashID($userID, 100);
    $this->message->setTable($table)->create([
        "msg_type"         => $msgType,
        "user_id"          => $userID,
        "comment_id"       => $commentID,
        "reply_comment_id" => $replyCommentID,
        "reply_user_id"    => $replyUserID,
        "game_id"          => $gameID,
        "is_read"          => 0,
        "created_at"       => date("Y-m-d H:i:s"),
    ]);
    return true;
}

这里 setTable 方法是在 Model 里定义的获取分表的方法:

public function setTable($table)
{
    $this->table = $table;
    return $this;
}

从报错日志中发现 $this->table 并没有生效,但实际上在调用 create 方法之前打印表名的时候是期望的值,这里调用 create 方法为什么 $this->table 没有被重置呢?

这里 $this->message 是一个继承 Model 类的模型类,其中 create 方法:

public static function create(array $attributes = [])
{
    $model = new static($attributes);
 
    $model->save();
 
    return $model;
}

位于 vendorlaravelframeworksrcIlluminateDatabaseEloquentModel.php Line 557.

因为 Laravel 框架的这个 Model 类是一个 abstract 类型,PHP 中 abstract 类可以用 new static 后期静态绑定的方式实例化,而 create 方法里 $model = new static($attributes) 实际上就是重新实例化了并返回,而调用者 Model 类没有定义 table 属性,所以这个时候 $this->table 是没有值的。

解决办法是用 save 方法即可,如图所示。实际上 create 方法也调用了 save 方法。

实验

一个抽象类 A,有个 create 方法,通过延迟静态绑定实例化并返回。B 类继承 A,test 方法中修改父类的 name 属性。

name = "Tony Tan";
        return $this;
    }
}
 
$obj1 = (new B)->test();
$obj2 = (new B)->test()->create();
var_dump($obj1);
var_dump($obj2);

结果显示 $obj1 和 $obj2 这两个实例都是 B 的实例,调用 test 方法属性 name 改变了,但是调用 create 方法后,name 属性并没有改变。这也就是在本文中说的在 Lavarel 中遇到的场景。(这里如果把注释打开,打印的 name 就是重写的值)

如果把抽象类 A 改成普通类,new static 改成 new self 的方式实例化,结果就不同了,打印的属性 name 都是各自类的属性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25623.html

相关文章

  • LaravelLaravel 框架关键技术解析·读书笔记(一)

    摘要:判断是否存在构造函数,不存在直接实例化,存在则通过来获取输入函数,并有相应的方法解决依赖参数问题,实现依赖注入。 Laravel 框架关键技术解析·读书笔记(一) 第一章 入口文件 请求访问的入口文件,主要完成几部分工作,分别是: 自动加载函数的添加 服务器实例化与服务注册 路由加载 请求实例化与路由分发 相应生成与发送 其中,自动加载函数用于包含引用文件,改文件是composer...

    CocoaChina 评论0 收藏0
  • 三年前旧代码的重构、总结与反思

    摘要:最近在维护一个三年前的旧代码,用的是框架。单元测试和语言并发控制实际上是个蛋疼的问题,夸张一点说,当时的并不能特别轻松地实现并发,甚至不能实现并发。语言的功能之一就是自带单元测试。用语言之前,我的习惯是不写单元测试。 最近在维护一个三年前的旧代码,用的是laravel框架。 从某些方面来讲,这个代码算是比较标准为了实现在规定的时间内完成相关功能,同时程序员水平不高、经过大量优化之后,变...

    Shihira 评论0 收藏0
  • Laravel中的核心概念

    摘要:可以为服务提供者的方法设置类型提示。方法将在所有其他服务提供者均已注册之后调用。所有服务提供者都在配置文件中注册。可以选择推迟服务提供者的注册,直到真正需要注册绑定时,这样可以提供应用程序的性能。 本文最早发布于 Rootrl的Blog 导言 Laravel是一款先进的现代化框架,里面有一些概念非常重要。在上手Laravel之前,我认为先弄懂这些概念是很有必要的。你甚至需要重温下PHP...

    ddongjian0000 评论0 收藏0
  • Laravel思维导图之Laravel核心概念

    摘要:的核心概念包括服务容器服务提供者门面契约。所有服务提供者都需要继承类。可以为服务提供者的方法设置类型提示。方法将在所有其他服务提供者均已注册之后调用。同样会整理成思维导图的形式以方便记忆与回顾。 showImg(https://segmentfault.com/img/remote/1460000010771201); Laravel 的核心概念包括:服务容器、服务提供者、门面(Fac...

    wthee 评论0 收藏0
  • Laravel 服务提供者和门面模式

    摘要:服务提供者先看看定义服务提供者是所有应用程序启动的中心所在。通过本文,希望大家能够了解服务提供者,,和实际调用的类的实例之间的关系。 以 Laravel 自带的文件系统为例,在 config/app.php 的配置文件的 providers 数组中,注册了一个服务提供者: IlluminateFilesystemFilesystemServiceProvider::class, 在 a...

    e10101 评论0 收藏0

发表评论

0条评论

30e8336b8229

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<