khởi tạo một lớp từ một biến trong PHP?


146

Tôi biết câu hỏi này nghe có vẻ mơ hồ vì vậy tôi sẽ làm cho nó rõ ràng hơn với một ví dụ:

$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');

Đây là những gì tôi muốn làm. Bạn sẽ làm điều này như thế nào? Tôi có thể tắt khóa học sử dụng eval () như thế này:

$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');

Nhưng tôi muốn tránh xa eval (). Có cách nào để làm điều này mà không có eval () không?

Câu trả lời:


213

Đặt tên lớp vào một biến đầu tiên:

$classname=$var.'Class';

$bar=new $classname("xyz");

Đây thường là thứ bạn sẽ thấy được gói trong một mẫu Factory.

Xem Không gian tên và các tính năng ngôn ngữ động để biết thêm chi tiết.


2
Đây là cách tôi làm điều đó. Lưu ý rằng từ bên trong các lớp bạn có thể sử dụng cha mẹ và bản thân.
Ross

1
Trên một lưu ý tương tự, bạn cũng có thể thực hiện $ var = 'Name'; $ obj -> {'get'. $ var} ();
Mario

1
Điểm hay, mặc dù chỉ hoạt động cho các cuộc gọi phương thức chứ không phải các nhà xây dựng
Paul Dixon

12
Nếu bạn làm việc với không gian tên, hãy đặt không gian tên hiện tại vào chuỗi:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey

@bastey - nhưng tại sao? Tôi chỉ dành quá nhiều thời gian để tìm hiểu, tại sao điều này sẽ không hoạt động mà không có không gian tên trước tên lớp ...
jkulak

72

Nếu bạn sử dụng không gian tên

Theo phát hiện của riêng tôi, tôi nghĩ thật tốt khi đề cập rằng bạn (theo như tôi có thể nói) phải khai báo đường dẫn không gian tên đầy đủ của một lớp.

MyClass.php

namespace com\company\lib;
class MyClass {
}

index.php

namespace com\company\lib;

//Works fine
$i = new MyClass();

$cname = 'MyClass';

//Errors
//$i = new $cname;

//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;

6
Giải pháp làm việc duy nhất khi cần tạo với không gian tên là của bạn. Cảm ơn đã chia sẻ!
Tiago Gouvêa

Nhưng điều này thật kỳ lạ, Tại sao nó không sử dụng không gian tên được khai báo?
Yisrael Dov

@YisraelDov Có, nó chắc chắn là phản trực quan. Nhưng vì lý do gì nó hành xử kỳ lạ trong bối cảnh này. Cảm ơn php
csga5000

@YisraelDov Tôi đoán là bởi vì trong trường hợp đó, việc tạo một lớp từ một không gian tên khác sẽ rất đau đầu. Cũng xem xét rằng các biến có thể được thông qua xung quanh. Khi tên lớp được viết dưới dạng văn bản thành tệp php, bất cứ ai viết nó đều biết chính xác không gian tên được viết. Nhưng khi một biến được truyền giữa các hàm, đó sẽ là một cơn ác mộng khi theo dõi nó. Ngoài ra, nếu bạn sử dụng get_group (), nó sẽ trả lại tên lớp FQ, do đó có thể được lưu trữ trong một biến ngay lập tức và được sử dụng ở bất cứ đâu. Nếu nó phụ thuộc vào không gian tên của tệp, nó sẽ không hoạt động tốt.
sbnc.eu

61

Làm thế nào để vượt qua các tham số xây dựng động quá

Nếu bạn muốn truyền tham số hàm tạo động cho lớp, bạn có thể sử dụng mã này:

$reflectionClass = new ReflectionClass($className);

$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);

Thông tin thêm về các lớp và tham số động

PHP> = 5,6

Kể từ phiên bản PHP 5.6, bạn có thể đơn giản hóa việc này hơn nữa bằng cách sử dụng Giải nén đối số :

// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);

Cảm ơn DisgruntledGoat đã chỉ ra điều đó.


7
Từ PHP 5.6, bạn sẽ có thể sử dụng giải nén đối số:new $className(...$params)
DisgruntledGoat

29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes

Không, không phải là một ví dụ tốt. Chỉ hoạt động nếu mọi thứ trong cùng một tệp php.
fralbo

2
2ndGAB nên xóa bình luận này. Tự động tải không có gì để làm với câu hỏi này.
Jim Maguire

-1

Tôi muốn giới thiệu các phương thức call_user_func()hoặc call_user_func_arrayphp. Bạn có thể kiểm tra chúng ở đây ( call_user_func_array , call_user_func ).

thí dụ

class Foo {
static public function test() {
    print "Hello world!\n";
}
}

 call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
 //or
 call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array

Nếu bạn có các đối số bạn đang truyền cho phương thức, sau đó sử dụng call_user_func_array()hàm.

thí dụ.

class foo {
function bar($arg, $arg2) {
    echo __METHOD__, " got $arg and $arg2\n";
}
}

// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));

3
Câu trả lời này không áp dụng cho câu hỏi. OP đang hỏi làm thế nào để NGAY LẬP TỨC một lớp (kích hoạt phương thức __construct một cách linh hoạt) từ một chuỗi biến và lấy lại MỤC TIÊU LỚP trong một biến mới - lời khuyên của bạn sẽ trả về GIÁ TRỊ của phương thức lớp-> ([]) bạn ' đang gọi lại, không phải đối tượng lớp nên không áp dụng cho trường hợp này. Xem giá trị trả về php.net/manual/en/feft.call-user-func-array.php
ChrisN
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.