1

次のようなクラス内のデータを動的に取得しようとしています:

Class foo
{
    private $config=array();

    public __construct(){    
        $this->config['site']['title'] = 'XXXXX';
        $this->config['site']['favicon'] = 'XXXXX.ico';
        $this->config['site']['keywords'] = array('page','cute','other');        
        $this->config['otherthing'] = 'value';
        /**etc**/
    }

    public function set($name,$value)
    {
        $tmp = explode('.',$name);
        /** i dont know what i can do here **/
    }

    public function get($name)
    {
        $tmp = explode('.',$name);
        /** i dont know what i can do here **/
    }
}

$thing = new foo;
$this->set('site.keywords',array('other','keywords'));//this change a data inside foo->config['site']['keywords']

echo $this->get('site.title'); // gets data inside foo->config['site']['title']
echo $this->get('otherthing'); // gets data inside foo->config['otherthing']

配列の次元は動的に変更でき、foo->config でデータを設定/取得したいのですが、ところで配列を呼び出します: function(fist.second.third.four.etc)。

編集:

爆発で関数を作成できます。その可能性を探りましたが、次のような関数を使用すると:

function get($name)
{
    $tmp = explode('.',$name);
    if(isset($this->config[$tmp[0]][$tmp[1]]))
        return $this->config[$tmp[0]][$tmp[1]];
    return '';
}

3 次元 ($this->config[one][two][tree]) または 1 次元 ($this->config[one]) の配列の値を取得する必要がある場合、関数は結果を処理できません。N次元の配列を取得したい。

私もこの解決策を試しました: $リターン = '';

    foreach($tmp as $v)
    {
        $return .= "['{$v}']";

    }

    return 'config'.$return;
}
function set($name,$value)
{
    $this->{$this->nameToArray} = $value;
}

$foo->set('site.favicon','something.ico');

しかし、これは $foo->config 内の配列を編集しません。これは文字通り config['site']['favicon'] と呼ばれる $this 内に新しい値を作成します。

どうすればできるのかわかりません。多くの方法を試しましたが、予想通りの結果が得られませんでした。手伝ってくれてありがとう。

4

3 に答える 3

1

参照を使用して、配列内の最新の既知のポイントを参照し、各ステップで更新します。

$ref = &$this->config;
$keys = explode('.', $name);
foreach ($keys as $idx => $key) {
    if (!is_array($ref)) {
        // reference does not refer to an array
        // this is a problem as we still have at least one key to go
    }
    if (!array_key_exists($key, $ref)) {
        // key does not exist
        // reaction depends on the operation
    }
    // update reference
    $ref = &$ref[$key];
}

ifブランチは操作によって異なります。ゲッターとセッターの例を次に示します。

public function get($name) {
    $ref = &$this->config;
    $keys = explode('.', $name);
    foreach ($keys as $idx => $key) {
        if (!is_array($ref)) {
            throw new Exception('key "'.implode('.', array_slice($keys, 0, $idx-1)).'" is not an array');
        }
        if (!array_key_exists($key, $ref)) {
            throw new Exception('key "'.implode('.', array_slice($keys, 0, $idx)).'" does not exist');
        }
        $ref = &$ref[$key];
    }
    return $ref;
}
public function set($name, $value) {
    $ref = &$this->config;
    $keys = explode('.', $name);
    foreach ($keys as $idx => $key) {
        if (!is_array($ref)) {
            throw new Exception('key "'.implode('.', array_slice($keys, 0, $idx)).'" is not an array but '.gettype($ref));
        }
        if (!array_key_exists($key, $ref)) {
            $ref[$key] = array();
        }
        $ref = &$ref[$key];
    }
    $ref = $value;
}
于 2012-08-05T08:58:30.693 に答える
1

eval に基づく別の解決策があります 文字列を括弧で連結するだけです

<?php
Class foo {
    private $config=array();

    function __construct(){    
        $this->config['site']['title'] = 'testing';
        $this->config['site']['favicon'] = 'XXXXX.ico';
        $this->config['site']['keywords'] = array('page','cute','other');        
        $this->config['otherthing'] = 'value';
        /**etc**/
    }

    public function set($name,$value)
    {
        $tmp = explode('.',$name);
        $array_levels = "['";
        foreach($tmp as $key) {
            $array_levels .= $key."']['";
        }
        $array_levels = substr($array_levels, 0, -2);
        eval('$this->config'.$array_levels.' = $value;');
    }
    public function get($name)
    {
        $tmp = explode('.',$name);
        $array_levels = "['";
        foreach($tmp as $key) {
            $array_levels .= $key."']['";
        }
        $array_levels = substr($array_levels, 0, -2);
        eval('$value = $this->config'.$array_levels.';');
        return $value;
    }
}
$thing = new foo;
$thing->set('site.keywords',array('other','keywords'));
echo $thing->get('site.title');
于 2012-08-05T09:27:52.653 に答える
0

ここでわかるように、関数explodeは文字列を受け取り、配列を返します。だからここにあなたがする必要があることです:

public function set($name,$value)
    {
        $tmp = explode('.',$name); //$tmp will now contain an array, so if $name = 'site.keywords'
                                   //$tmp[0] will contain 'site' and $tmp[1] = 'keywords'
        //if you send 'otherthing' as $name, then $tmp[1] will have no value
        if(isset($tmp[1])){
                $this->config[$tmp[0]][$tmp[1]] = $value; // this is like saying  $this-config['site']['keywords'] = $value
        }
        else{
            $this->config[$tmp[0]] = $value; 
        }
    }

そして、取得のために:

public function get($name)
    {
        $tmp = explode('.',$name);
        if(isset($tmp[1])){
            return $this->config[$tmp[0]][$tmp[1]];
        }
        else{
           return $this->config[$tmp[0]];
        }

    }
于 2012-08-05T08:44:45.080 に答える