【问题标题】:Can't exit a loop after all checks return false在所有检查返回 false 后无法退出循环
【发布时间】:2019-11-17 14:49:41
【问题描述】:

我有一些方法可以检查命令的响应,并根据该响应执行其他操作,或者失败。

我已经把它带到了它检查命令输出并返回 false 的地方,然后继续执行其余的代码。

这里有一些代码

public function upgradeImages($images)
{
    $this->pull($images);

    echo "Do next method - Fake destroy\n";

    echo "Do next method - Fake re-build\n";
}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);

    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);
        }

        echo("'$image' is at the latest version");
    }
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}

这里发生的情况是,upgradeImage 运行 pull 方法,pull 方法正在检查 Docker 映像数组并循环查看映像是否有新版本。这是通过运行isNewVersion() 方法来完成的,该方法检查$buffer 的输出并进行比较。

如果isNewVersion() 返回true,它将循环并更新图像。

如果 isNewVersion() 返回 false,它会通过一条消息告诉您它是最新的。

如果该方法返回 false,我希望循环在 ALL 检查发生后退出,而不是在 $this->pull() 之后继续运行 upgradeImages 方法中的代码。如果我在检查后添加exit,它将在第一次检查后退出,而不检查循环的其余部分。

假设我选择了 2 个图像进行更新,并且两者都 不需要 需要更新,输出将是这样的:

Updrading 2 containers...
'composer:latest' is at the latest version
'php:7.2-fpm-alpine' is at the latest version
Fake destroy
Fake re-build

【问题讨论】:

  • 您能提供一个示例输出吗?
  • 更新了一些输出的帖子
  • 我明白了,在这种情况下,期望的行为是不运行破坏并重新构建吗?
  • 正确,如果没有要更新的图像,则不需要运行destroy/re-build方法
  • 您是否考虑过使用 ansible 而不是 PHP 来编写您的逻辑?它可以让你的生活更轻松,你会或多或少地免费获得幂等性。例如通过 ansible 拉取图像可以使用此处描述的 docker_image 模块存档:docs.ansible.com/ansible/latest/modules/…

标签: php loops docker symfony foreach


【解决方案1】:

根据您的问题(在所有检查返回 false 后无法退出循环) 如果你想在条件满足你的要求的情况下停止执行,你可以使用Break强制停止它;

查看更多信息 https://www.php.net/manual/en/control-structures.break.php

【讨论】:

  • 我试过这个。似乎无论我把它放在哪里,它都不起作用。也许你有一些最佳用例的例子?
【解决方案2】:

这样的?

public function upgradeImages($images)
{
    $imagesUpdated = $this->pull($images);

    if ($imagesUpdated > 0) {
        echo "Do next method - Fake destroy\n";

        echo "Do next method - Fake re-build\n";

    } else {
        // do nothing or explicit call 'exit' if you want
    }


}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);
    $countUpdated = 0;
    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);
            $countUpdated++;
        }

        echo("'$image' is at the latest version");
    }
    return $countUpdated;
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}

【讨论】:

  • 这种方式对我有用,我喜欢它。将深入研究它,看看它是否适合目的。感谢您的贡献!
【解决方案3】:

upgradeImages 方法可以有多个销毁/重新构建。不要在pull 中这样做,而是创建另一个可以多次调用的方法。我已将其命名为 doUpgrade() 并将其传递给 $image 以进行升级。

public function upgradeImages($images)
{
    $this->pull($images);
}

public function doUpgrade($image)
{
    echo "Do next method - Fake destroy\n";
    echo "Do next method - Fake re-build\n";
}

public function pull($images)
{
    // Count how many containers will be attempted to be updated
    $countImages = count($images);

    echo("Updrading $countImages containers...");

    foreach ($images as $key => $image) {
        $key = $key + 1;

        // Is there a new version of the image?
        if ($this->isNewVersion($image)) {
            echo("($key/$countImages) Upgrading '$image'");

            $this->docker('pull ' . $image);

            /* call the destroy/re-build */
            echo("'$image' being upgraded");
            $this->doUpgrade($image);
        }

        echo("'$image' is at the latest version");
    }
}

public function isNewVersion($image)
{
    $cmdOutput = (new Process($this->docker('pull ' . $image)));
    $cmdOutput->start();

    $cmdOutput->wait(function ($type, $buffer) {
        if (contains($buffer, 'Image is up to date')) {
            return false;
        }

        return true;
    });
}

【讨论】:

  • 这不会在foreach 循环的第一次迭代中返回,破坏它吗?我认为最好在函数开头声明$ret = false;,仅在需要时将true分配给它(如果图像已更新),然后在foreach循环之外返回return $ret;,这样您确定只有图像确实更新了才会是真的。
  • 但它会返回。退货就是退货,您不能“撤消”退货。我仍然认为最好的方法是在第一个函数中循环遍历数组,并从第一个函数调用循环内的下一个函数。
  • 我试过这个方法,效果很好——可以满足我的需要。将对其进行更多研究,如果它适合目的,我将标记为最佳答案。虽然这种情况对于其他有类似问题的人来说可能不是最好的,但它确实帮助了我!谢谢!
猜你喜欢
  • 2012-10-14
  • 1970-01-01
  • 2016-12-20
  • 2013-03-21
  • 2015-01-23
  • 2020-11-23
  • 2017-02-27
  • 2020-06-06
  • 1970-01-01
相关资源
最近更新 更多