文字列でPHPクラスプロパティを取得する


139

文字列に基づいてPHPでプロパティを取得するにはどうすればよいですか?それを呼ぶよmagic。だから何magicですか?

$obj->Name = 'something';
$get = $obj->Name;

のようになります...

magic($obj, 'Name', 'something');
$get = magic($obj, 'Name');

回答:


241

このような

<?php

$prop = 'Name';

echo $obj->$prop;

または、クラスを制御できる場合は、ArrayAccessインターフェイスを実装して、これを実行します

echo $obj['Name'];

最初のオプションよりも2番目のオプションを使用する利点は何ですか?
Clox

2
@Clox一般に、配列のように変数を使用する既存のシステムがあり、オブジェクトによって提供される柔軟性とパワーが必要な場合に後者を使用する主な利点。クラスが実装した場合ArrayAccessCountableおよびイテレータ・インタフェースの一つは、それが正常からほとんど区別がつかないのですarray()
ピーター・ベイリー

158

中間変数を作成せずにプロパティにアクセスする場合は、{}表記法を使用します。

$something = $object->{'something'};

これにより、たとえば、ループでプロパティ名を作成することもできます。

for ($i = 0; $i < 5; $i++) {
    $something = $object->{'something' . $i};
    // ...
}

8
これは、配列値にアクセスする場合にのみ使用できます$this->{$property}[$name]。そうでない場合$this->$property[$name]はエラーがスローされます
goyote

@goyote:値とPHPのバージョンによって異なります。5.3では、プロパティがまだ有効でないPHP構文であるため、「エラー」ではなくプロパティが見つからないため、E_NOTICEがトリガーされます。それは可能性があります$this->$property[$name]、これはバグである可能性が高いものの、かもしれないが、実際に成功します。$name静かに整数にキャストされます。非数値文字列の場合、これは0です。次に、この値の文字列インデックス$propertyプロパティ名として使用されます。$property値「abc」を保持している場合、これはプロパティ$this->a(インデックス0)を参照します。そのようなプロパティがある場合、これは成功します。
MrWhite 2013年

@goyote:ただし、PHP 5.4では、数値以外の文字列インデックスは暗黙的に整数0にキャストされず、E_WARNINGがトリガーされます。
MrWhite 2013年

13

あなたが尋ねているのは変数変数です。必要なのは、文字列を変数に格納し、次のようにアクセスすることだけです。

$Class = 'MyCustomClass';
$Property = 'Name';
$List = array('Name');

$Object = new $Class();

// All of these will echo the same property
echo $Object->$Property;  // Evaluates to $Object->Name
echo $Object->{$List[0]}; // Use if your variable is in an array

3
変数変数は別のものです。
オラフルWaage

2
問題は、名前が文字列(変数)に含まれている場合に、クラスプロパティ(変数)を取得する方法です。それとも質問を誤解しましたか?
マッピー2009

8

このようなもの?テストはしていませんが、問題なく動作するはずです。

function magic($obj, $var, $value = NULL)
{
    if($value == NULL)
    {
        return $obj->$var;
    }
    else
    {
        $obj->$var = $value;
    }
}

2
+1、文字列を使用してオブジェクトのプロパティにアクセスできることを知りませんでした。
Marco Demaio 2011年

5

プロパティ名を変数に格納し、変数を使用してプロパティにアクセスするだけです。このような:

$name = 'Name';

$obj->$name = 'something';
$get = $obj->$name;


4

単純です。$ obj-> {$ obj-> Name}中かっこは、変数変数のようにプロパティをラップします。

これは上位の検索でした。しかし、これは$ thisを使用していた私の質問を解決しませんでした。中括弧を使用する私の状況の場合にも役立ちました...

Code Igniterのインスタンスを取得する例

親クラスのインスタンスを持つ何かと呼ばれるソースライブラリクラス内

$this->someClass='something';
$this->someID=34;

親インスタンスを含む別のクラスからのソースを必要とするライブラリクラス

echo $this->CI->{$this->someClass}->{$this->someID};

2

ちょうど追加として:この方法では、他の方法では使用できない名前を持つプロパティにアクセスできます

$ x =新しいStdClass;

$ prop = 'a b'; $ x-> $ prop = 1; $ x-> {'x y'} = 2; var_dump($ x);

オブジェクト(stdClass)#1(2){
  ["a b"] =>
  int(1)
  ["x y"] =>
  int(2)
}
(そうすべきではありませんが、万が一に備えて)。
あなたも、手の込んだものをしたい場合は、になっているはずです反射


1

他の誰かが未知の深さの深いプロパティを見つけたい場合、私はすべての子供たちのすべての既知のプロパティをループする必要なしに以下を思いつきました。

たとえば、$ Foo-> Bar-> baz、または$ Foo-> baz、または$ Foo-> Bar-> Baz-> daveを検索するには、$ pathは 'foo / bar / baz'のような文字列です。

public function callModule($pathString, $delimiter = '/'){

    //split the string into an array
    $pathArray = explode($delimiter, $pathString);

    //get the first and last of the array
    $module = array_shift($pathArray);
    $property = array_pop($pathArray);

    //if the array is now empty, we can access simply without a loop
    if(count($pathArray) == 0){
        return $this->{$module}->{$property};
    }

    //we need to go deeper
    //$tmp = $this->Foo
    $tmp = $this->{$module};

    foreach($pathArray as $deeper){
        //re-assign $tmp to be the next level of the object
        // $tmp = $Foo->Bar --- then $tmp = $Bar->baz
        $tmp = $tmp->{$deeper};
    }

    //now we are at the level we need to be and can access the property
    return $tmp->{$property};

}

そして、次のように呼び出します:

$propertyString = getXMLAttribute('string'); // '@Foo/Bar/baz'
$propertyString = substr($propertyString, 1);
$moduleCaller = new ModuleCaller();
echo $moduleCaller->callModule($propertyString);

0

これが私の試みです。いくつかの一般的な「愚かさ」チェックが組み込まれているので、利用できないメンバーを設定または取得しないでください。

これらの「property_exists」チェックをそれぞれ__setおよび__getに移動して、magic()内で直接呼び出すことができます。

<?php

class Foo {
    public $Name;

    public function magic($member, $value = NULL) {
        if ($value != NULL) {
            if (!property_exists($this, $member)) {
                trigger_error('Undefined property via magic(): ' .
                    $member, E_USER_ERROR);
                return NULL;
            }
            $this->$member = $value;
        } else {
            if (!property_exists($this, $member)) {
                trigger_error('Undefined property via magic(): ' .
                    $member, E_USER_ERROR);
                return NULL;
            }
            return $this->$member;
        }
    }
};

$f = new Foo();

$f->magic("Name", "Something");
echo $f->magic("Name") , "\n";

// error
$f->magic("Fame", "Something");
echo $f->magic("Fame") , "\n";

?>

0

この関数が行うことは、子のこのクラスにプロパティが存在するかどうかをチェックし、存在する場合は値を取得し、それ以外の場合はnullを返します。したがって、プロパティはオプションで動的になります。

/**
 * check if property is defined on this class or any of it's childes and return it
 *
 * @param $property
 *
 * @return bool
 */
private function getIfExist($property)
{
    $value = null;
    $propertiesArray = get_object_vars($this);

    if(array_has($propertiesArray, $property)){
        $value = $propertiesArray[$property];
    }

    return $value;
}

使用法:

const CONFIG_FILE_PATH_PROPERTY = 'configFilePath';

$configFilePath = $this->getIfExist(self::CONFIG_FILE_PATH_PROPERTY);

-6
$classname = "myclass";
$obj = new $classname($params);

$variable_name = "my_member_variable";
$val = $obj->$variable_name; //do care about the level(private,public,protected)

$func_name = "myFunction";
$val = $obj->$func_name($parameters);

なぜ編集するか:before:eval(evil)を使うafter:evalをまったく使わない。この言語で古いこと。


これは非常に悪いアドバイスです。eval()関数は非常に危険なツールであり、インジェクション攻撃に対して非常に脆弱です。 blog.highub.com/php/php-core/php-eval-is-evilが情報を提供するはずです。
ridecar2

3
この回答を削除すると、バッジが付与されます。
テルメッチ2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.