3

タグの配列があるとします

$all_tags = array('A', 'B', 'C');

そして、$_GET 変数を使用して一連の URL を作成したいと考えています。
リンクを次のようにしたいと思います:
'A'リンク先への"index.php?x[]=B&x[]=C"
'B'リンク先"index.php?x[]=A&x[]=C"
など ($_GET は、「現在の」要素を除くすべての要素を含む配列です) (これを実装する簡単な方法があることは知っています: 実際には、より複雑なものを単純化しています)状況)

array_filter()これを使って解決したいと思います。
これが私の試みです:

function make_get ($tag) { return 'x[]=' . $tag; }
function tag_to_url ($tag_name) {
   global $all_tags;

   $filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);'); 
   return 'index.php?' . implode('&', array_map("make_get", array_filter($all_tags, "filta")));
}
print_r(array_map("", $all_tags));

しかし、うまくいきません。PHPのマップとフィルターが実際にデータ構造自体を変更し、機能的なスタイルを使用する代わりにブール値を返す方法に関係している可能性があるのではないかと疑っています。

このコードをより簡潔にする他の方法にも興味があります。

4

4 に答える 4

2

別のアプローチを次に示します。

// The meat of the matter
function get_link($array, $tag) {
    $parts = array_reduce($array, function($result, $item) use($tag)
                          {
                              if($item != $tag) $result[] = 'x[]='.$tag;
                              return $result;
                          });
    return implode('&', $parts);
}

// Test driver

$all_tags = array('A', 'B', 'C');

echo get_link($all_tags, 'A');
echo "\n";
echo get_link($all_tags, 'B');
echo "\n";
echo get_link($all_tags, 'C');
echo "\n";

を 1 回呼び出してからarray_reduce、 を呼び出しimplodeて結果をまとめてクエリ文字列にするだけです。

于 2011-12-07T18:56:36.090 に答える
1

コメントで与えた回答に基づいて(ここに表示):

<?php

  $all_tags = array('A', 'B', 'C');

  function tag_to_url($tag_name)
  {
    global $all_tags;

    $remaining_tags = array_diff($all_tags, array($tag_name));
    return sprintf('index.php?%s', 
             http_build_query(array('x'=>array_values($remaining_tags))));
  }

  echo tag_to_url('B'); // index.php?x%5B0%5D=A&x%5B1%5D=C
                        // basically: index.php?x[0]=A&x[1]=C

基本的に、 を使用array_diffして (フィルタリングする代わりに) 配列からエントリを削除し、それを に渡してhttp_build_query有効な URL を見つけます。

于 2011-12-07T18:49:02.503 に答える
1

「なぜうまくいかないのか」の部分に答えるだけです。

$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);'); 

tag_name 変数は、ラムダ関数のスコープで未定義です。現在、作成関数のスコープ (tag_to_url)で定義されています。$tag_name はグローバル スコープではなく、ローカルの tag_to_url スコープにあるため、ここでも global キーワードを正確に使用することはできません。グローバルスコープで変数を宣言することもできますが、機能する可能性がありますが、関数型アプローチが好きであることを考えると、グローバル変数が好きだとは思えません:)

必要に応じて、文字列連結と var_export($tag_name) を使用してトリッキーを実行し、それを create_function() に渡すこともできますが、目標を達成するためのより良い方法は他にもあります。

また、余談ですが、開発中にphpのエラー報告レベルを上げることで利益が得られると思います。php は、未定義の変数通知をスローするため、デバッグと理解に役立ちます。

// ideally set these in php.ini instead of in the script
error_reporting(E_ALL);
ini_set('display_errors', 1);
于 2011-12-07T19:01:57.697 に答える
1

PHP での関数型プログラミング スタイルの真のサポートに近づいているものは、非常に新しいものです。関数がファースト クラスになり、無名関数が可能になったのは PHP 5.3 になってからです。

ところで、決して使用しないでくださいcreate_function()。それが実際に行うことは、グローバル名前空間で新しい関数を定義することです (これは決してガベージ コレクションされません!)、それはeval()舞台裏で使用されます。

PHP 5.3 以降を使用している場合は、次のようにすることができます。

$all_tags = array('A', 'B', 'C');

function is_not_equal($a, $b) {
    return $a != $b;
}

function array_filter_tagname($alltags, $name) {
    $isNotEqualName = function($item) use ($name){
        return is_not_equal($item, $name);
    };
    // array_merge() is ONLY to rekey integer keys sequentially.
    // array_filter() preserves keys.
    return array_merge(array_filter($alltags, $isNotEqualName));
}

function make_url($arr) {
    return 'input.php?'.http_build_query(array('x'=>$arr));
}
$res = array_filter_tagname($all_tags, 'B');
print_r($res);
print_r(make_url($res));

PHP < 5.3 を使用している場合は、クロージャーにcreate_function().

class NotEqualName {
    protected $otheritem;
    function __construct($otheritem) { // with PHP 4, use "function NotEqualName($otheritem) {"
        $this->otheritem = $otheritem;
    }
    function compare($item) {
        return $item != $this->otheritem;
    }
}

function array_filter_tagname_objectcallback($alltags, $name) {
    $isNotEqualName = new NotEqualName($name);
    return array_merge(array_filter($alltags, array($isNotEqualName,'compare')));
}

ただし、一般的に、PHP は機能的なスタイルにはあま​​り適しておらず、特定のタスクで使用するarray_filter()PHP はあまり慣用的ではありません。array_diff()より良いアプローチです。

于 2011-12-07T19:17:50.780 に答える