hyperf / hyperf

🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.
https://www.hyperf.io
MIT License
6.27k stars 1.22k forks source link

view-engine包中的loop是不是存在数据错乱的可能 #6921

Open cceessff opened 5 months ago

cceessff commented 5 months ago
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace Hyperf\ViewEngine\Concern;

use Countable;
use Hyperf\Collection\Arr;
use stdClass;

trait ManagesLoops
{
    /**
     * The stack of in-progress loops.
     */
    protected array $loopsStack = [];

    /**
     * Add new loop to the stack.
     *
     * @param null|array|Countable $data
     */
    public function addLoop($data)
    {
        $length = is_countable($data) ? count($data) : null;

        $parent = Arr::last($this->loopsStack);

        $this->loopsStack[] = [
            'iteration' => 0,
            'index' => 0,
            'remaining' => $length ?? null,
            'count' => $length,
            'first' => true,
            'last' => isset($length) ? $length == 1 : null,
            'odd' => false,
            'even' => true,
            'depth' => count($this->loopsStack) + 1,
            'parent' => $parent ? (object) $parent : null,
        ];
    }

    /**
     * Increment the top loop's indices.
     */
    public function incrementLoopIndices()
    {
        $loop = $this->loopsStack[$index = count($this->loopsStack) - 1];

        $this->loopsStack[$index] = array_merge($this->loopsStack[$index], [
            'iteration' => $loop['iteration'] + 1,
            'index' => $loop['iteration'],
            'first' => $loop['iteration'] == 0,
            'odd' => ! $loop['odd'],
            'even' => ! $loop['even'],
            'remaining' => isset($loop['count']) ? $loop['remaining'] - 1 : null,
            'last' => isset($loop['count']) ? $loop['iteration'] == $loop['count'] - 1 : null,
        ]);
    }

    /**
     * Pop a loop from the top of the loop stack.
     */
    public function popLoop()
    {
        array_pop($this->loopsStack);
    }

    /**
     * Get an instance of the last loop in the stack.
     *
     * @return null|stdClass|void
     */
    public function getLastLoop()
    {
        if ($last = Arr::last($this->loopsStack)) {
            return (object) $last;
        }
    }

    /**
     * Get the entire loop stack.
     *
     * @return array
     */
    public function getLoopStack()
    {
        return $this->loopsStack;
    }
}

这里的 $loopsStack 是所有携程共用的,如果 A协程往其中写入数据 a, B协程往其中写入数据b,然后再有多个携程区获取当前的loop,是不是获取到的可能不是自己协程的数据

tadink commented 4 months ago

这个问题没人知道吗? @limingxinleo @huangzhhui

limingxinleo commented 4 months ago

这个有用到么?

tadink commented 4 months ago

这个有用到么?

在模板中有用到,并且我还发现 Hyperf\ViewEngine\Factory 里面的 shared 属性可能会有同样的问题。在 Hyperf\ViewEngine\Http\Middleware\ShareErrorsFromSession 里面

$errors = $this->session->get('errors') ?: new ViewErrorBag();
 $this->view->share('errors', $errors); 

这个中间件是每个请求都会执行的,这个 errors 不会被覆盖吗