3

基本的に配列のラッパーであり、IteratorAggregateを実装するクラスがあります。クラスの新しいオブジェクトが作成されると、その値が$valueという保護された変数に格納されます。値は、文字列、整数など、またはトラバース可能なオブジェクト(配列など)にすることができます。

トラバース可能なオブジェクト(配列など)がコンストラクターに渡されると、クラスの別のインスタンスが作成されるため、このオブジェクトは「再帰的」です。明確にするためのコンストラクターは次のとおりです。

class ListItem implements \IteratorAggregate
{
    protected $readOnly = false;
    protected $key;
    protected $value;

    public function __construct($key, $value, $readOnly = false)
    {
        if($readOnly) $this->readOnly = true;
        if(is_numeric($key)) $key = 'index'.$key;
        $this->key = $key;

        if (is_array($value) || $value instanceof Traversable) {
            $this->value = array();
            foreach($value as $k => $v) {
                if(is_numeric($k)) $k = 'index'.$k;
                $this->value[$k] =  new ListItem($k, $v, $readOnly);
            }
        } else {
            $this->value = $value;
        }
    }

    public function __toString()
    {
        if ( is_array($this->value) ) {
            return 'ListItem OBJECT(' . count($this->value) . ')';
        } else {
            return $this->value;
        }
    }

今、私はクラスの簡単なソートメソッドを書こうとしています。

キーで並べ替えると、これは魅力のように機能します。

$success = ksort($this->value, $comparison);

ただし、値で並べ替える場合、並べ替えようとしている実際の値はvalueプロパティ内に格納されているため、asortは機能しません。

だから私はこのようにuasortを使ってみました:

   $success = uasort($this->value, function ($a, $b)
   {                    
      if ($a->value == $b->value) return 0;
      else if($a->value < $b->value) return -1;
      else return 1;
   });

しかし、いくつかの不明確な理由で、次のエラーが発生します。

警告:uasort()[function.uasort]:129行目の/ * / * /*/ListItem.phpのユーザー比較関数によって配列が変更されました


Q.比較のために$valueにアクセスしているだけで、実際には何も変更されていないのに、なぜこれが発生するのですか?

4

1 に答える 1

1

クロージャ(または無名関数)がグローバルスコープにあるようです。つまり、オブジェクトuasortのプライベートまたは保護されたメンバーにアクセスできませんでしたListItem(ただし、他のListItemオブジェクトは兄弟のプライベート/保護されたプロパティにアクセスできます)

これで問題は解決しました:(文字列へのキャスト)

$success = uasort($this->value, function ($objA, $objB) use ($comparison)
{
    $a = (string) $objA;
    $b = (string) $objB;
    if($comparison == ListItem::SORT_NUMERIC) {
        if (is_numeric($a)) $a = (int) $a;
        if (is_numeric($b)) $b = (int) $b;
    }                   
    if ($a == $b) return 0;
    else if($a < $b) return -1;
    else return 1;
});
于 2012-10-20T21:40:21.040 に答える