0
class Operation
{
    private $op;

    public function __construct()
    {
        $this->op = [];
        for ($i = 1; $i < 1000; $i++)
        {
            $this->op[] = rand(1,9999);
        }
    }

    public function getOps()
    {
        return $this->op;
    }
}

class TestTellDontAsk
{
    public function doItBAD(Operation $op)
    {
        foreach($op->getOps() as $item)
        {
            echo $item.'; ';
        }
    }

    public function doItGOOD(array $ops)
    {
        foreach($ops as $item)
        {
            echo $item.'; ';
        }
    }
}

$m = [
    memory_get_peak_usage(true),
    memory_get_peak_usage(false),
    memory_get_peak_usage(true),
    memory_get_peak_usage(false)
];
$op = new Operation();
switch(mt_rand(0,1))
{
    case 0: (new TestTellDontAsk())->doItBAD($op); break;
    case 1: (new TestTellDontAsk())->doItGOOD($op->getOps()); break;
}
echo '<hr>';
echo memory_get_peak_usage(true) - $m[0].'<br>';
echo memory_get_peak_usage(false) - $m[1].'<br>';
echo memory_get_peak_usage(true) - $m[2].'<br>';
echo memory_get_peak_usage(false) - $m[3].'<br>';

这在 BAD 和 GOOD 用法中展示了整体。

doItBAD()很糟糕,因为传递一个对象对于函数来说是不必要的知识,但 MEMORY-GOOD,因为它只是传递一个引用,而不是整个数组本身

doItGOOD()很好,因为它只传递一个数组,但 MEMORY-BAD,因为它只传递所有数据而不是引用。

现在如何决定使用哪一个?

4

1 回答 1

1

这是一个比简单的“告诉不要问”更广泛的问题。这里有两个概念。权衡一个与另一个是很常见的。

  • 好的软件设计
  • 高效的软件设计

这两个概念都是主观的。什么是好的代码是无休止的争论。“高效”软件根据上下文有多种不同的含义(例如:在 CPU 上高效,或在内存上高效)。

因此,对这个问题的任何回答都将是主观的并且有待商榷。有人会说这不是一个好的堆栈溢出问题。

什么时候为了效率而写“不太好”的代码?

这是经验。

如果您没有经验,那么这里有一些提示:

  • 这段代码对性能有多重要?它是一天执行一次还是一天执行十亿次,有一百万个并发线程?
  • 性能影响有多大?不必担心每天损失 1 秒的 CPU 时间。不值得担心奇数 KB 的 RAM。但如果这段代码是 500MB 或 1/2MB 之间的差异,那么也许你应该仔细考虑一下。
  • 你违反了多少原则?如果一个类中的 9/10 函数采用对象,而只有一个函数只能采用数组,那么您不太可能对代码进行太多改进。您实际上可能违反了最小惊讶原则
  • 开发时间。假设您的时间按每小时 100 美元计费?当一个不完美的答案可以在 5 分钟内完成时,找到这个问题的完美答案是否值得你花 2 小时的时间?有时答案是“是的!”。很多时候答案是“不”。

经验法则

坏:如果您没有性能要求,那么永远不要担心性能。 我花了太多年时间修复那些人的代码。这是一种虚假的经济。

更好:如果您没有具体的理由担心性能,那么就不要……而是随时测试性能。这样,您的代码在投入生产时可能实际上可以工作。

更清楚的是:以牺牲性能为代价追求好的设计。仅在需要时推动性能。

于 2017-08-05T14:34:29.287 回答