Nhận thuộc tính lớp PHP theo chuỗi


139

Làm cách nào để có được một thuộc tính trong PHP dựa trên chuỗi? Tôi sẽ gọi nó magic. Vậy là magicgì?

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

sẽ giống như ...

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

Câu trả lời:


241

Như thế này

<?php

$prop = 'Name';

echo $obj->$prop;

Hoặc, nếu bạn có quyền kiểm soát lớp, hãy triển khai giao diện ArrayAccess và chỉ cần làm điều này

echo $obj['Name'];

Bất kỳ lợi ích của việc sử dụng tùy chọn thứ hai so với đầu tiên?
Clox

2
@Clox Nói chung, lợi ích chính của việc sử dụng cái sau nếu bạn có một hệ thống hiện có tiêu thụ một biến theo cách giống như mảng, nhưng bạn muốn sự linh hoạt và sức mạnh được cung cấp bởi các đối tượng. Nếu một dụng cụ lớp ArrayAccess, Countablevà một trong những giao diện iterator, nó chủ yếu là không thể phân biệt từ một bình thườngarray()
Peter Bailey

158

Nếu bạn muốn truy cập thuộc tính mà không tạo biến trung gian, hãy sử dụng {}ký hiệu:

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

Điều đó cũng cho phép bạn xây dựng tên thuộc tính trong một vòng lặp chẳng hạn:

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

8
Đây là cách duy nhất nếu bạn muốn truy cập một giá trị mảng $this->{$property}[$name], nếu không $this->$property[$name]sẽ gây ra lỗi
goyote

@goyote: Nó phụ thuộc vào các giá trị và phiên bản PHP. Trong 5.3, nó kích hoạt E_NOTICE vì không thể tìm thấy thuộc tính, thay vì "lỗi", vì nó vẫn là cú pháp PHP hợp lệ. Có thể điều đó $this->$property[$name]thực sự có thể thành công, mặc dù đây có thể là một lỗi. $nameđược âm thầm đúc thành một số nguyên. Trong trường hợp của một chuỗi không phải là số 0. Sau đó, chỉ số chuỗi này của giá trị $propertyđược sử dụng làm tên thuộc tính. Nếu $propertygiữ giá trị "abc", thì điều này sẽ đề cập đến thuộc tính $this->a(chỉ số 0). Nếu có một tài sản như vậy thì điều này sẽ thành công.
MrWhite

@goyote: Tuy nhiên, trong PHP 5.4, chỉ mục chuỗi không phải là số không âm thầm được chuyển sang số nguyên 0, nó sẽ kích hoạt E_WARNING.
MrWhite

13

Những gì bạn đang hỏi về được gọi là Biến biến . Tất cả bạn cần làm là lưu trữ chuỗi của bạn trong một biến và truy cập nó như vậy:

$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
Biến số là một điều khác.
Ólafur Chờ đợi

2
Câu hỏi là làm thế nào để có được một thuộc tính lớp (biến) khi tên được chứa trong một chuỗi (biến). Hay tôi đã đọc sai câu hỏi?
matpie

8

Một cái gì đó như thế này? Không thử nghiệm nó nhưng sẽ hoạt động tốt.

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

2
+1, không biết thuộc tính đối tượng có thể được tích lũy bằng chuỗi.
Marco Demaio

5

Chỉ cần lưu trữ tên thuộc tính trong một biến và sử dụng biến đó để truy cập thuộc tính. Như thế này:

$name = 'Name';

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

5

Có thể có câu trả lời cho câu hỏi này, nhưng bạn có thể muốn xem những chuyển đổi này sang PHP 7

thay đổi không tương thích ngược

nguồn: php.net


4

Thật đơn giản, $ obj -> {$ obj-> Name}, dấu ngoặc nhọn sẽ bao bọc thuộc tính giống như một biến số.

Đây là một tìm kiếm hàng đầu. Nhưng không giải quyết được câu hỏi của tôi, đó là sử dụng $ this. Trong trường hợp hoàn cảnh của tôi, sử dụng dấu ngoặc nhọn cũng giúp ...

ví dụ với Code Igniter lấy ví dụ

trong một lớp thư viện có nguồn gốc gọi là một cái gì đó với một thể hiện của lớp cha

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

lớp thư viện cần lấy nguồn từ lớp khác cũng với thể hiện cha mẹ

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

2

Cũng như một sự bổ sung: Bằng cách này, bạn có thể truy cập các thuộc tính có tên không thể sử dụng được

$ x = StdClass mới;

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

đối tượng (stdClass) # 1 (2) {
  ["a b"] =>
  int (1)
  ["X y"] =>
  int (2)
}
(không phải là bạn nên, nhưng trong trường hợp bạn phải).
Nếu bạn muốn làm những thứ thậm chí huyền ảo hơn, bạn nên nhìn vào sự phản chiếu


1

Trong trường hợp bất kỳ ai khác muốn tìm một tài sản sâu không rõ độ sâu, tôi đã đưa ra cách dưới đây mà không cần phải lặp qua tất cả các thuộc tính đã biết của tất cả trẻ em.

Ví dụ: để tìm $ Foo-> Bar-> baz hoặc $ Foo-> baz hoặc $ Foo-> Bar-> Baz-> dave, trong đó $ path là một chuỗi như '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};

}

Và sau đó gọi với một cái gì đó như:

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

0

Đây là nỗ lực của tôi. Nó có một số kiểm tra 'ngu ngốc' phổ biến được tích hợp sẵn, đảm bảo bạn không cố gắng thiết lập hoặc có được một thành viên không có sẵn.

Bạn có thể di chuyển các kiểm tra 'property_exists' đó thành __set và __get tương ứng và gọi chúng trực tiếp trong ma thuật ().

<?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

Hàm này làm gì là nó kiểm tra xem thuộc tính có tồn tại trên lớp này của bất kỳ đứa con nào không và nếu có thì nó sẽ nhận được giá trị nếu không nó sẽ trả về null. Vì vậy, bây giờ các thuộc tính là tùy chọn và năng động.

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

Sử dụng:

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

why chỉnh sửa: trước: sử dụng eval (ác) sau: không có eval nào cả. đã cũ trong ngôn ngữ này.


Đây là lời khuyên rất tệ, hàm eval () là một công cụ rất nguy hiểm và sẽ khiến bạn cực kỳ dễ bị tấn công. blog.highub.com/php/php-core/php-eval-is-evil sẽ cung cấp cho bạn một số thông tin.
Ridecar2

3
Xóa câu trả lời này và bạn sẽ có một huy hiệu!
Thermech
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.