0

次のPHPサンプルコードは、「bar」要素が「foo」要素の前にある場合にのみ機能します。順序が間違っていると、「非オブジェクトでのメンバー関数の呼び出し」エラーが発生します。

$data = array();
foreach($elems as $e) {
  if($e['type'] == "foo") {
    $data[$e["key"]->foo_data($e["data_foo"]);
  }
  elseif($e['type'] == "bar") {
    $data[$e["key"]] = new Bar($e);
  }
}

現時点での私の解決策は、を2回繰り返すこと$elemsです。別の解決策はusort、「foo」要素の前に「bar」要素を配置するカスタムソート関数で使用することです。

要素を任意の順序で処理できるプログラミングパターンやライブラリはありますか?

4

3 に答える 3

0

2回ループするのが、最も賢明な解決策のようです。1回ループしてオブジェクトを準備し、2回ループしてそれらのオブジェクトにデータを処理させます。まったく異なる、より良い解決策があるかもしれませんが、より具体的なユースケースを見ずにそれを言うのは難しいです。

于 2012-10-19T13:22:15.807 に答える
0

実用的なアプローチは、順不同で表示されるものに耐性のある中間データ表現を使用してから、データをもう一度パスしてデータを完成させることです。たとえば、次のようになります。

foreach($elems as $e) {
  if($e['type'] == "foo") {
    $data[$e["key"]]["foo_data"] = $e["data_foo"];
  }
  elseif($e['type'] == "bar") {
    $data[$e["key"]]["bar"] = new Bar($e);
  }
}

foreach ($data as &$d) {
    $foo_data = $d["foo_data"];
    $d = $d["bar"];
    $d->foo_data($foo_data);
}

同様の代替方法は、データを段階的に修正することです。これは、別のループを必要としませんが、修正ロジックを実際のデータ抽出ロジックと結合し、DRYに違反するため、さらに悪化します。

foreach($elems as $e) {
  if($e['type'] == "foo") {
    if (isset($data[$e["key"]])) {
        $data[$e["key"]]->foo_data($e["data_foo"]); // normal operation
    }
    else {
        $data[$e["key"]] = $e["data_foo"]; // temporary result
    }

  }
  elseif($e['type'] == "bar") {
    if (isset($data[$e["key"]])) {  // incremental fix
      $bar = new Bar($e); 
      $bar->foo_data($data[$e["key"]]);
      $data[$e["key"]] = $bar;
    else {
      $data[$e["key"]]["bar"] = new Bar($e); // normal operation
    }
  }
}

最後に、もちろん、他の(よく設計された)アプローチを選択して、ループの再実行と「不正なコード」の記述の両方を回避することもできますが、PHPではそれが容易ではなく、疑わしい利益のために大量のコードを記述してしまうことになります。

一般的な推奨事項:一時的なデータ表現を保持し、最後にもう一度ループします。

于 2012-10-19T13:28:04.530 に答える
0

わかりました。プロキシパターンを使用するソリューションは次のとおりです。

class BarProxy {
    private $callstack = array();
    public function __call($name, $arguments) {
        $this->callstack[] = array($name, $arguments);
    }

    public function createBar($params) {
        $bar = new Bar($params);
        foreach($this->callstack as $call) {
            call_user_func_array(array($bar, $call[0]), $call[1]);
        }
        return $bar;
    }
}

class BarData {
    private $data = array();

    public function getBar($id) {
        if(!isset($this->data[$id])) {
            $this->data[$id] = new BarProxy();
        }
    }

    public function createBar($id, $params) {
        if(!isset($this->data[$id])) {
            $this->data[$id] = new Bar($params);
        }
        elseif($this->data[$id] instanceof BarProxy) {
            $this->data[$id] = $this->data[$id]->createBar($params);
        }
    }

    // Other methods for getting the data, maybe implement Iterator or ArrayAccess 
}


$data = new BarData();
foreach($elems as $e) {
  if($e['type'] == "foo") {
    $data->getBar($e["key"])->foo_data($e["data_foo"]);
  }
  elseif($e['type'] == "bar") {
    $data->createBar($e["key"], $e);
  }
}

長所:ifこのコードは、forループにステートメントが散らかることを回避します。クラスは独自のファイルにあり、ループはクリーンで理解しやすいままです。2つのクラスをさらに抽象化して、任意のクラスをプロキシおよび格納できます。

短所:このソリューションには、関数呼び出しと2つの追加クラスが必要になるため、パフォーマンスとメモリ消費量は、2回ループするよりもおそらく劣ります。

于 2012-10-19T14:13:50.730 に答える