刚开始用laravel模型时,为了方便一直写静态方法,进行数据库操作。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
public static function getList()
{
return self::get()->toArray();
}
}

直到有朋友告诉可以不用这么写,声明一个 protected 方法,方法中用 $this。在外部使用时,也可以像调静态函数一样调用。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
protected function getList()
{
return $this->get()->toArray();
}
}

试了一下,发现还真可以,按理说受保护的 protected 非静态方法,在外部是无法这么调用的 User::getList() 。

但是在 laravel 中就可以,查看了下 Model 基类的代码,原来是因为实现了 __call() 和 __callStatic() 这两个魔术方法。

class Model
{
public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return $this->$method(...$parameters);
} return $this->forwardCallTo($this->newQuery(), $method, $parameters);
} public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
}

我们试着自已实现下这两个魔术方法,看看效果。

<?php

namespace App\Models;

class Model
{
//在对象中调用一个不可访问方法时,__call()被调用
public function __call($method, $parameters)
{
echo '__call()';
return $this->{$method}(...$parameters);
} //在静态上下文中调用一个不可访问方法时,__callStatic()被调用
public static function __callStatic($method, $parameters)
{
echo '__callStatic()';
//注意这里,通过延迟静态绑定,仍然new了一个实例
return (new static)->{$method}(...$parameters);
} private function test()
{
echo '被调用了<br>';
}
}

我们尝试调用 test() 方法。

<?php

namespace App\Http\Controllers\Test;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Model; class Test extends Controller
{
public function index(Request $request)
{
//对象调用
(new Model())->test(); //静态方法调用
Model::test();
}
}

结果显示调用成功。

laravel模型中非静态方法也能静态调用的原理的更多相关文章

  1. "静态方法里仅仅能调用静态变量和静态方法"具体解释

    静态方法里能够调用静态方法和静态变量,同一时候也能调用非静态方法和非静态变量. public class Test { public Test() {}; public Test(int i) {th ...

  2. php静态调用非静态方法

    <?php /** * php静态调用非静态方法 * author: 百里 * Date: 2019/7/18 * Time: 17:28 */ function dump(...$var) { ...

  3. Laravel模型事件的实现原理详解

    模型事件在 Laravel 的世界中,你对 Eloquent 大多数操作都会或多或少的触发一些模型事件,下面这篇文章主要给大家介绍了关于Laravel模型事件的实现原理,文中通过示例代码介绍的非常详细 ...

  4. Laravel 模型事件入门

    Laravel 模型事件允许你监听模型生命周期内的多个关键点,甚至可以在阻止一个模型的保存或者删除. Laravel 模型事件文档 概述了如何使用钩子将对应事件与相关的事件类型关联起来,但是本文的主旨 ...

  5. Java中的静态方法和实例方法的调用的理解(不同的类下的方法调用)

    public class MethodCall { public static void main(String[] args) { Test.sayStatic(); Test test = new ...

  6. 在Delphi中静态调用DLL

    在Delphi中静态调用DLL top 调用一个DLL比写一个DLL要容易一些.首先给大家介绍的是静态调用方法,稍后将介绍动态调用方法,并就两种方法做一个比较.同样的,我们先举一个静态调用的例子. u ...

  7. 【VB技巧】VB静态调用与动态调用dll详解

    本文“[VB技巧]VB静态调用与动态调用dll详解”,来自:Nuclear'Atk 网络安全研究中心,本文地址:http://lcx.cc/?i=489,转载请注明作者及出处! [[请注意]]:在以下 ...

  8. C++调用DLL有两种方法——静态调用和动态调用

    C++调用DLL有两种方法——静态调用和动态调用 标签: dllc++winapinullc 2011-09-09 09:49 11609人阅读 评论(0) 收藏 举报  分类: cpp(30)  [ ...

  9. jQuery扩展两类函数(对象调用,静态调用)

    作者:zccst 先看小例子: $(function(){ //扩展方式1-通过对新调用 $.fn.each1=function(){ console.log("hehehehe$.fn.f ...

随机推荐

  1. 手写SpringMVC实现过程

    1. Spring Boot,Spring MVC的底层实现都是Servlet的调用. 2. Servlet的生命周期里面首先是类的初始化,然后是类的方法的调用,再次是类的销毁. 3. 创建一个spr ...

  2. JDK1.8新特性——使用新的方式遍历集合

    JDK1.8新特性——使用新的方式遍历集合 摘要:本文主要学习了在JDK1.8中新增的遍历集合的方式. 遍历List 方法: default void forEach(Consumer<? su ...

  3. HTTP中的2XX状态码

    HTTP状态码分类 1XX --信息,服务器收到请求,需要请求者继续执行操作 2XX--成功,操作被成功接收并处理 3XX--重定向,需要进一步的操作以完成请求 4XX--客户端错误,请求包含语法错误 ...

  4. 「SAP技术」SAP MM 事务代码ME17的用法

    SAP MM 事务代码ME17的用法 1,如下采购信息记录需要被归档: PIR号码,5300007816   2, ME12打上删除标记,   3, 事务代码ME17做归档 3.1 创建archive ...

  5. Quest 公司的Shareplex 与 GoldenGate比较

    Quest 公司的Shareplex 与 GoldenGate比较     2012-08-01 16:51:12 —————————————————————————————————————————— ...

  6. 渗透测试学习 二十三、常见cms拿shell

    常见cms 良精.科讯.动易.aspcms.dz 米拓cms.phpcms2008.帝国cms.phpv9 phpweb.dedecms 良精 方法: 1.数据库备份拿shell 上传图片——点击数据 ...

  7. Incorrect datetime value: '' for column 'examDate' at row 1

    出问题的程序:user.setCreateTime(new Date()); 控制台图片一张,问题是:Incorrect datetime value: '' for column 'createTi ...

  8. 7.3 DStream操作

    一.Spark Streaming工作机制 在Spark Streaming中,会有一个组件Receiver,作为一个长期运行的task跑在一个Executor上: 每个Receiver都会负责一个i ...

  9. 高频Python面试题分享

    一.Python语言中你用过哪些方式来实现进程间通信1.队列Queue 2.Pipe管道 只适用于两个进程之间的通信, pipe的效率高于queue 3.共享内存 4.socket套接字(UDP即可) ...

  10. fiddler设置https抓包

    代理端口设置:127.0.0.1:8888 https抓包设置 模拟post请求: http://xxx.xxxx.com/portal/login.htm Cookie: xxxx account= ...