Uzyskaj właściwość klasy PHP według ciągu

139

Jak uzyskać właściwość w PHP na podstawie ciągu znaków? Zadzwonię magic. Więc co to jest magic?

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

byłoby jak ...

magic($obj, 'Name', 'something');
$get = magic($obj, 'Name');
Daniel A. White
źródło

Odpowiedzi:

241

Lubię to

<?php

$prop = 'Name';

echo $obj->$prop;

Lub, jeśli masz kontrolę nad klasą, zaimplementuj interfejs ArrayAccess i po prostu zrób to

echo $obj['Name'];
Peter Bailey
źródło
Jakieś korzyści z używania drugiej opcji w stosunku do pierwszej?
Clox
2
@Clox Ogólnie rzecz biorąc, główna korzyść z używania tego drugiego, jeśli masz istniejący system, który zużywa zmienną w sposób podobny do tablicy, ale chcesz elastyczności i mocy oferowanej przez obiekty. Jeżeli narzędzi klasy ArrayAccess, Countablei jeden z interfejsów iterator, to przeważnie nie do odróżnienia od normalnegoarray()
Peter Bailey
158

Jeśli chcesz uzyskać dostęp do właściwości bez tworzenia zmiennej pośredniej, użyj {}notacji:

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

Pozwala to również na utworzenie pętli nazwy właściwości, na przykład:

for ($i = 0; $i < 5; $i++) {
    $something = $object->{'something' . $i};
    // ...
}
laurent
źródło
8
Jest to jedyny sposób, jeśli chcesz uzyskać dostęp do wartości tablicy $this->{$property}[$name], w przeciwnym razie $this->$property[$name]wystąpi błąd
goyote
@goyote: To zależy od wartości i wersji PHP. W 5.3 wywołuje E_NOTICE, ponieważ nie można znaleźć właściwości, a nie „błąd”, ponieważ nadal jest to poprawna składnia PHP. Możliwe, że $this->$property[$name]faktycznie się uda, chociaż prawdopodobnie jest to błąd. $namejest po cichu rzutowany na liczbę całkowitą. W przypadku łańcucha nieliczbowego jest to 0. Następnie ten indeks łańcucha wartości $propertyjest używany jako nazwa właściwości. Jeśli $propertyzawiera wartość „abc”, będzie to odwoływać się do właściwości $this->a(indeks 0). Jeśli istnieje taka właściwość, to się powiedzie.
MrWhite
@goyote: Jednak w PHP 5.4 nieliczbowy indeks łańcucha nie jest po cichu rzutowany na liczbę całkowitą 0, wywoła to E_WARNING.
MrWhite
13

To, o co pytasz, nazywa się zmiennymi zmiennymi . Wszystko, co musisz zrobić, to zapisać ciąg w zmiennej i uzyskać do niego dostęp w następujący sposób:

$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
matpie
źródło
3
Zmienne zmienne to inna sprawa.
Ólafur Waage
2
Pytanie brzmi, jak uzyskać właściwość klasy (zmienną), gdy nazwa jest zawarta w ciągu (zmiennej). A może źle odczytałem pytanie?
matpie
8

Coś takiego? Nie testowałem tego, ale powinno działać dobrze.

function magic($obj, $var, $value = NULL)
{
    if($value == NULL)
    {
        return $obj->$var;
    }
    else
    {
        $obj->$var = $value;
    }
}
Ólafur Waage
źródło
2
+1, nie wiedziałem, że właściwości obiektu można uzyskać za pomocą łańcuchów.
Marco Demaio
5

Po prostu zapisz nazwę właściwości w zmiennej i użyj tej zmiennej, aby uzyskać dostęp do właściwości. Lubię to:

$name = 'Name';

$obj->$name = 'something';
$get = $obj->$name;
Jon Benedicto
źródło
5

Mogą istnieć odpowiedzi na to pytanie, ale możesz chcieć zobaczyć te migracje do PHP 7

zmiana niekompatybilna wstecz

źródło: php.net

Muhammad Maulana
źródło
4

To jest proste, $ obj -> {$ obj-> Name} nawiasy klamrowe będą opakowywać właściwość podobnie jak zmienna zmienna.

To było najlepsze wyszukiwanie. Ale nie rozwiązało mojego pytania, które dotyczyło $ this. W moim przypadku użycie nawiasu kręconego też pomogło ...

przykład z Code Igniter get instancję

w źródłowej klasie biblioteki o nazwie coś z instancją klasy nadrzędnej

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

klasa biblioteki musi pobierać źródła z innej klasy również z instancją nadrzędną

echo $this->CI->{$this->someClass}->{$this->someID};
Mark Allen
źródło
2

Tylko jako dodatek: w ten sposób można uzyskać dostęp do właściwości o nazwach, które w innym przypadku byłyby bezużyteczne

$ x = nowa klasa StdClass;

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

object (stdClass) # 1 (2) {
  ["a b"] =>
  int (1)
  ["x y"] =>
  int (2)
}
(nie to, że powinieneś, ale na wypadek, gdybyś musiał).
Jeśli chcesz robić jeszcze bardziej wyszukane rzeczy, powinieneś przyjrzeć się refleksji

VolkerK
źródło
1

Na wypadek, gdyby ktoś chciał znaleźć głęboką właściwość o nieznanej głębokości, wymyśliłem poniżej bez konieczności przeglądania wszystkich znanych właściwości wszystkich dzieci.

Na przykład, aby znaleźć $ Foo-> Bar-> baz lub $ Foo-> baz lub $ Foo-> Bar-> Baz-> dave, gdzie $ path jest ciągiem znaków, takim jak „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};

}

A potem zadzwoń z czymś takim:

$propertyString = getXMLAttribute('string'); // '@Foo/Bar/baz'
$propertyString = substr($propertyString, 1);
$moduleCaller = new ModuleCaller();
echo $moduleCaller->callModule($propertyString);
Jordan Whitfield
źródło
0

Oto moja próba. Ma wbudowane pewne typowe testy `` głupoty '', dzięki którym nie próbujesz ustawiać ani pobierać członka, który nie jest dostępny.

Możesz przenieść te sprawdzenia 'property_exists' odpowiednio do __set i __get i wywołać je bezpośrednio w 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";

?>
Nick Presta
źródło
0

Funkcja ta sprawdza, czy właściwość istnieje w tej klasie którejkolwiek z jego dzieci, a jeśli tak, to pobiera wartość, w przeciwnym razie zwraca wartość null. Więc teraz właściwości są opcjonalne i dynamiczne.

/**
 * 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;
}

Stosowanie:

const CONFIG_FILE_PATH_PROPERTY = 'configFilePath';

$configFilePath = $this->getIfExist(self::CONFIG_FILE_PATH_PROPERTY);
Mahmoud Zalt
źródło
-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);

dlaczego edit: before: using eval (evil) after: no eval all. bycie starym w tym języku.

r4ccoon
źródło
To bardzo zła rada, funkcja eval () jest bardzo niebezpiecznym narzędziem i naraża Cię na ataki iniekcyjne. blog.highub.com/php/php-core/php-eval-is-evil powinien dać ci trochę informacji.
ridecar2
3
Usuń tę odpowiedź, a otrzymasz odznakę!
Thermech,