รับคุณสมบัติคลาส 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'];

ประโยชน์ของการใช้ตัวเลือกที่สองในช่วงแรก?
Clox

2
@Clox โดยทั่วไปประโยชน์หลักของการใช้งานหลังถ้าคุณมีระบบที่มีอยู่ซึ่งใช้ตัวแปรในลักษณะที่คล้ายกับอาร์เรย์ แต่คุณต้องการความยืดหยุ่นและพลังงานที่นำเสนอโดยวัตถุ หากมีการดำเนินการระดับArrayAccess, Countableและเป็นหนึ่งในอินเตอร์เฟซ iterator มันเป็นส่วนใหญ่แตกต่างจากปกติ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 มันทริกเกอร์ E_NOTICE เนื่องจากไม่พบคุณสมบัติแทน "ข้อผิดพลาด" เนื่องจากยังคงเป็นไวยากรณ์ PHP ที่ถูกต้อง เป็นไปได้ที่$this->$property[$name]อาจประสบความสำเร็จจริง ๆ แม้ว่านี่จะเป็นข้อผิดพลาด $nameถูกส่งไปยังจำนวนเต็มแบบไม่มีการโต้ตอบ 0ในกรณีของสตริงที่ไม่ใช่ตัวเลขนี้เป็น จากนั้นสตริงดัชนีนี้ของค่าที่$propertyใช้เป็นชื่อคุณสมบัติ หาก$propertyเก็บค่า "abc" สิ่งนี้จะอ้างถึงคุณสมบัติ$this->a(ดัชนี 0) หากมีคุณสมบัติเช่นนี้ก็จะประสบความสำเร็จ
MrWhite

@Goyote: อย่างไรก็ตามใน PHP 5.4 ดัชนีสตริงที่ไม่ใช่ตัวเลขนั้นไม่ได้ถูกส่งไปยังเลขจำนวนเต็ม 0 อย่างเงียบ ๆ มันจะทริกเกอร์ E_WARNING
MrWhite

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
ตัวแปรตัวแปรเป็นอีกสิ่งหนึ่ง
--lafur Waage

2
คำถามคือวิธีรับคุณสมบัติคลาส (ตัวแปร) เมื่อชื่อมีอยู่ในสตริง (ตัวแปร) หรือฉันทำผิดคำถาม?
matpie

8

อะไรแบบนี้? ยังไม่ได้ทดสอบ แต่ควรใช้งานได้ดี

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

2
+1 ไม่ทราบว่าคุณสมบัติของวัตถุสามารถถูก accesed โดยใช้สตริง
Marco Demaio

5

เพียงแค่เก็บชื่อคุณสมบัติในตัวแปรและใช้ตัวแปรเพื่อเข้าถึงคุณสมบัติ แบบนี้:

$name = 'Name';

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


4

มันง่าย $ obj -> {$ obj-> ชื่อ} วงเล็บปีกกาจะล้อมรอบคุณสมบัติเหมือนกับตัวแปรตัวแปร

นี่เป็นการค้นหายอดนิยม แต่ไม่ได้แก้ไขคำถามของฉันซึ่งใช้ $ นี่ ในกรณีของฉันที่ใช้ตัวยึดแบบโค้งก็ช่วยได้ ...

ตัวอย่างกับ 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);

object (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

ฟังก์ชั่นนี้ทำหน้าที่ตรวจสอบว่ามีทรัพย์สินอยู่ในชั้นเรียนของลูกของเขาหรือไม่และถ้าเป็นเช่นนั้นมันจะได้รับค่ามิฉะนั้นจะคืนค่าว่าง ดังนั้นตอนนี้คุณสมบัติเป็นทางเลือกและแบบไดนามิก

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

ทำไมแก้ไข: ก่อน: ใช้ eval (ชั่วร้าย) หลัง: ไม่มีหลักฐานเลย แก่ตัวในภาษานี้


นี่เป็นคำแนะนำที่แย่มากฟังก์ชั่น eval () เป็นเครื่องมือที่อันตรายมากและจะทำให้คุณเสี่ยงต่อการถูกโจมตีจากการฉีดยา blog.highub.com/php/php-core/php-eval-is-evilควรให้ข้อมูลบางอย่างแก่คุณ
ridecar2

3
ลบคำตอบนี้แล้วคุณจะมีป้าย!
Thermech
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.