douyouqian8550 2019-06-14 03:58
浏览 76

PHP回声似乎不按顺序发生

I am working on a personal project, building out some basic functionality to handle PHP components so they can be built in a similar way to components in React. I've encountered some strange behavior, where if I render a component inline using string interpolation, it appears before the place it is invoked in code. I am able to get the markup to display correctly by running each step as its own line of code, but I'd like to be able to include these components in strings. Why could this out-of-order rendering be happening? Any insight would be greatly appreciated.

I have tried to return the included components instead of echo them, but (maybe because of the double quotes used?) they do not render at all doing so. I have also concatenated the components together as strings. This does not work. If I write distinct lines of code and end with a semicolon after each one, I get the expected result.

This is what I would like to have working:

    echo "
        <section class='videoInfo'>
            <h1>{$props[$video]->getProperty(VIDEO_PROP::TITLE)}</h1>
            <div class='secondary'>
                <span class='viewCount'>{$props[$video]->getProperty(VIDEO_PROP::VIEWS)} views</span>
                {$loader::render(COMPONENT::OPINION_CONTROLS)}
                {$loader::render(COMPONENT::VIDEO_DETAILS)}
            </div>
        </section>
    ";

I have also tried this, which results in the same mangled output as above:

    echo "
        <section class='videoInfo'>
            <h1>{$props[$video]->getProperty(VIDEO_PROP::TITLE)}</h1>
            <div class='secondary'>
                <span class='viewCount'>{$props[$video]->getProperty(VIDEO_PROP::VIEWS)} views</span>" .
                $loader::render(COMPONENT::OPINION_CONTROLS) .
                $loader::render(COMPONENT::VIDEO_DETAILS) .
            "</div>
        </section>
    ";

This works correctly, but is more cumbersome to write:

    echo "
        <section class='videoInfo'>
            <h1>{$props[$video]->getProperty(VIDEO_PROP::TITLE)}</h1>
            <div class='secondary'>
                <span class='viewCount'>{$props[$video]->getProperty(VIDEO_PROP::VIEWS)} views</span>";
                $loader::render(COMPONENT::OPINION_CONTROLS);
                $loader::render(COMPONENT::VIDEO_DETAILS);
        echo "</div>
        </section>
    ";

I expect the output HTML to reflect the echoed string. So the final output should look like:

<section class="videoInfo">
            <h1>Second Test</h1>
            <div class="secondary">
                <span class="viewCount">86 views</span>
        <!-- includes javascript for handling like/dislike buttons -->
        <script src="assets/js/opinions.js"></script>
        <div class="controls">

            <button class="opinion far fa-thumbs-up" onclick="like(this, 60)">
                <span class="text">0</span>
            </button>


            <button class="opinion far fa-thumbs-down" onclick="dislike(this, 60)">
                <span class="text">0</span>
            </button>

        </div>

        <!-- includes javascript for handling edit/subscribe buttons -->
        <script src="assets/js/videoInteractions.js"></script>
        <section class="details">
            <nav>

            <a href="profile.php?username=testman">
                <img src="assets/images/generic_profile.png" class="profilePic">
            </a>

            </nav>
            <div class="uploadInfo">
                <span class="uploader">
                    <a href="profile.php?username=testman">
                        testman
                    </a>
                </span>
                <span class="uploadDate">
                    Published on Jun 4, 2019
                </span>
            </div>

            <button class="subscribe " onclick="subscribe(&quot;chan123&quot;, &quot;testman&quot;, this)">
                <span class="text">Subscribe 0</span>
            </button>

            <section class="description">
                Testing view incrementing
            </section>
        </section>
    </div>
        </section>

This is indeed the output I get if I run each step as a distinct line of code. If I use string interpolation or concatenation, however, the components load out of order. The loaded components in fact appear before the videoInfo section altogether!



            <button class="opinion far fa-thumbs-up" onclick="like(this, 60)">
                <span class="text">0</span>
            </button>


            <button class="opinion far fa-thumbs-down" onclick="dislike(this, 60)">
                <span class="text">0</span>
            </button>


            <nav>

            <a href="profile.php?username=testman">
                <img src="assets/images/generic_profile.png" class="profilePic">
            </a>

            </nav>
            <div class="uploadInfo">
                <span class="uploader">
                    <a href="profile.php?username=testman">
                        testman
                    </a>
                </span>
                <span class="uploadDate">
                    Published on Jun 4, 2019
                </span>
            </div>

            <button class="subscribe " onclick="subscribe(&quot;chan123&quot;, &quot;testman&quot;, this)">
                <span class="text">Subscribe 0</span>
            </button>

            <section class="description">
                Testing view incrementing
            </section>

            <h1>Second Test</h1>
            <div class="secondary">
                <span class="viewCount">87 views</span>


            </div>

The output components are themselves echoed strings. They look like this:

(opinionControls)

    echo "
        <!-- includes javascript for handling like/dislike buttons -->
        <script src='assets/js/opinions.js'></script>
        <div class='controls'>
            $likeButton
            $dislikeButton
        </div>
    ";

(videoDetails)

    echo "
        <!-- includes javascript for handling edit/subscribe buttons -->
        <script src='assets/js/videoInteractions.js'></script>
        <section class='details'>
            <nav>
                $profileButton
            </nav>
            <div class='uploadInfo'>
                <span class='uploader'>
                    <a href='profile.php?username=$uploader'>
                        $uploader
                    </a>
                </span>
                <span class='uploadDate'>
                    Published on $formattedDate
                </span>
            </div>
            $interactButton
            <section class='description'>
                {$props[$video]->getProperty(VIDEO_PROP::DESCRIPTION)}
            </section>
        </section>
    ";

Do nested echoes somehow bubble out of the top level echo? I am trying to wrap my head around this behavior.

I have tried to adjust the nested components by having them return strings instead of doing an echo, but I have had no luck getting them to render at all this way. I have tried single quotes and double quotes around the returned strings. Like so:

    return '
        <!-- includes javascript for handling like/dislike buttons -->
        <script src=\'assets/js/opinions.js\'></script>
        <div class=\'controls\'>
            $likeButton
            $dislikeButton
        </div>
    ';

and

    return "
        <section class='videoInfo'>
            <h1>{$props[$video]->getProperty(VIDEO_PROP::TITLE)}</h1>
            <div class='secondary'>
                <span class='viewCount'>{$props[$video]->getProperty(VIDEO_PROP::VIEWS)} views</span>
                {$loader::render(COMPONENT::OPINION_CONTROLS)}
                {$loader::render(COMPONENT::VIDEO_DETAILS)}
            </div>
        </section>
    ";

The $loader::render() function is fairly straightforward. It calls a function which invokes include() on a component that has been primed a little earlier in the application. The relevant ComponentLoader functions follow:

    // Load component into static primedComponents array as a key, with its value its props
    public static function primeComponentWithProps(string $includesPath, array $props)
    {
        self::$primedComponents[$includesPath] = $props;
    }
    // Extract component and props from static array, then include it on the page
    public static function render(string $includesPath)
    {
        $props = self::$primedComponents[$includesPath];
        $args = [$includesPath, $props];

        self::loadComponentWithProps(...$args);
        // remove the component from the array of primed components once it has been rendered
        unset(self::$primedComponents[$includesPath]);
    }

    /** used to import components that require props */
    public static function loadComponentWithProps(string $includesPath, array $props)
    {
        // extract($props);     // using extract() would allow props to be accessed directly by key names--but currently we are using a props array and accessing values by key to make it clearer what is going on in components which consume props
        include($includesPath);
    }
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 Vue3 大型图片数据拖动排序
    • ¥15 划分vlan后不通了
    • ¥15 GDI处理通道视频时总是带有白色锯齿
    • ¥20 用雷电模拟器安装百达屋apk一直闪退
    • ¥15 算能科技20240506咨询(拒绝大模型回答)
    • ¥15 自适应 AR 模型 参数估计Matlab程序
    • ¥100 角动量包络面如何用MATLAB绘制
    • ¥15 merge函数占用内存过大
    • ¥15 使用EMD去噪处理RML2016数据集时候的原理
    • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大