V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
OMGZui
V2EX  ›  PHP

Laravel 源码 Collection(集合)请教

  •  
  •   OMGZui · 2018-06-07 11:45:47 +08:00 · 3099 次点击
    这是一个创建于 2396 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Collection.php

    /**
     * @property-read HigherOrderCollectionProxy $average
     * @property-read HigherOrderCollectionProxy $avg
     * @property-read HigherOrderCollectionProxy $contains
     * @property-read HigherOrderCollectionProxy $each
     * @property-read HigherOrderCollectionProxy $every
     * @property-read HigherOrderCollectionProxy $filter
     * @property-read HigherOrderCollectionProxy $first
     * @property-read HigherOrderCollectionProxy $flatMap
     * @property-read HigherOrderCollectionProxy $groupBy
     * @property-read HigherOrderCollectionProxy $keyBy
     * @property-read HigherOrderCollectionProxy $map
     * @property-read HigherOrderCollectionProxy $max
     * @property-read HigherOrderCollectionProxy $min
     * @property-read HigherOrderCollectionProxy $partition
     * @property-read HigherOrderCollectionProxy $reject
     * @property-read HigherOrderCollectionProxy $sortBy
     * @property-read HigherOrderCollectionProxy $sortByDesc
     * @property-read HigherOrderCollectionProxy $sum
     * @property-read HigherOrderCollectionProxy $unique
     *
     * Class Collection
     */
    
        /**
         * The methods that can be proxied.
         *
         * @var array
         */
        protected static $proxies = [
            'average', 'avg', 'contains', 'each', 'every', 'filter', 'first',
            'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition',
            'reject', 'sortBy', 'sortByDesc', 'sum', 'unique',
        ];
    
        /**
         * Dynamically access collection proxies.
         *
         * @param  string  $key
         * @return mixed
         *
         * @throws \Exception
         */
        public function __get($key)
        {
            if (! in_array($key, static::$proxies)) {
                throw new Exception("Property [{$key}] does not exist on this collection instance.");
            }
    
            return new HigherOrderCollectionProxy($this, $key);
        }
    

    HigherOrderCollectionProxy.php

        /**
         * Create a new proxy instance.
         *
         * @param  \Illuminate\Support\Collection  $collection
         * @param  string  $method
         * @return void
         */
        public function __construct(Collection $collection, $method)
        {
            $this->method = $method;
            $this->collection = $collection;
        }
    
        /**
         * Proxy accessing an attribute onto the collection items.
         *
         * @param  string  $key
         * @return mixed
         */
        public function __get($key)
        {
            return $this->collection->{$this->method}(function ($value) use ($key) {
                return is_array($value) ? $value[$key] : $value->{$key};
            });
        }
    
        /**
         * Proxy a method call onto the collection items.
         *
         * @param  string  $method
         * @param  array  $parameters
         * @return mixed
         */
        public function __call($method, $parameters)
        {
            return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
                return $value->{$method}(...$parameters);
            });
        }
    

    我的问题是这里为什么要用 HigherOrderCollectionProxy 来代理,有什么好处?这些方法都是 public 形式的,直接调用方法不好吗?

    9 条回复    2018-06-08 15:55:07 +08:00
    websterq
        1
    websterq  
       2018-06-07 12:09:18 +08:00
    链式调用,Laravel 里挺常见的设计吧,这样设计也是为了方便、流程的 Code 体验
    crystom
        2
    crystom  
       2018-06-07 12:12:57 +08:00
    User 类有 sendEmail 方法
    则可以用这样的写法:
    $users->each->sendEmail();
    等价于$users->each(function($user){$user->sendEmail()});
    OMGZui
        3
    OMGZui  
    OP
       2018-06-07 14:07:44 +08:00
    @websterq 老哥,我确定这不是链式调用,比如(new Collection([1, 2]))->max()->min(),这样是不行的。
    DavidNineRoc
        4
    DavidNineRoc  
       2018-06-07 14:41:54 +08:00   ❤️ 3
    看文档呀,这个是 高阶函数调用,简单的来说就是本来你的 User 对象有一个 toArray 方法,
    这时候你有一集合 User 对象都要调用 toArray 方法可以
    $users->each->toArray();
    echo 是集合的方法,toArray 是 User 的方法;这样子高阶代理使用非常简单,不然你得这样操作
    $usersArray = new HigherOrderCollectionProxy($users, 'toArray');

    ## 想要链式调用的时候就不能了,
    $users->tap()->map()->each->toArray();
    上面的操作,如果不用高阶代理函数,就要拆成两部分了
    OMGZui
        5
    OMGZui  
    OP
       2018-06-07 15:08:05 +08:00
    @DavidNineRoc 老哥,我大概是懂了。
    xxstop
        6
    xxstop  
       2018-06-07 22:06:21 +08:00
    战略性 mark
    OMGZui
        7
    OMGZui  
    OP
       2018-06-08 15:09:04 +08:00
    @xxstop 兄弟,这也 mark 啊
    xxstop
        8
    xxstop  
       2018-06-08 15:53:54 +08:00
    @OMGZui #7 感动。你这么一说,我在网上找到一篇很棒的文章。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2771 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:04 · PVG 18:04 · LAX 02:04 · JFK 05:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.