instantiate kelas dari variabel dalam PHP?

146

Saya tahu pertanyaan ini kedengarannya agak kabur sehingga saya akan membuatnya lebih jelas dengan sebuah contoh:

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

Ini yang ingin saya lakukan. Bagaimana Anda melakukannya? Tentunya saya bisa menggunakan eval () seperti ini:

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

Tapi saya lebih suka menjauh dari eval (). Apakah ada cara untuk melakukan ini tanpa eval ()?

Pim Jager
sumber

Jawaban:

215

Masukkan nama kelas ke dalam variabel terlebih dahulu:

$classname=$var.'Class';

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

Ini sering kali Anda lihat terbungkus dalam pola Pabrik.

Lihat Ruang nama dan fitur bahasa dinamis untuk detail lebih lanjut.

Paul Dixon
sumber
2
Beginilah cara saya melakukannya. Perhatikan bahwa dari dalam kelas Anda dapat menggunakan induk dan mandiri.
Ross
1
Pada catatan yang sama, Anda juga dapat melakukan $ var = 'Name'; $ obj -> {'get'. $ var} ();
Mario
1
Poin bagus, meskipun itu hanya berfungsi untuk pemanggilan metode dan bukan konstruktor
Paul Dixon
12
Jika Anda bekerja dengan namespace, masukkan namespace saat ini ke dalam string:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey
@astey - tapi mengapa? Saya hanya menghabiskan terlalu banyak waktu untuk mencari tahu, mengapa ini tidak akan berhasil tanpa ruang nama sebelum nama kelas ...
jkulak
72

Jika Anda Menggunakan Namespaces

Dalam temuan saya sendiri, saya pikir itu baik untuk menyebutkan bahwa Anda (sejauh yang saya tahu) harus menyatakan jalur namespace penuh kelas.

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;
csga5000
sumber
6
Satu-satunya solusi yang berfungsi ketika harus dibuat dengan namespace, adalah milik Anda. Terima kasih sudah berbagi!
Tiago Gouvêa
Tapi ini aneh, Mengapa tidak menggunakan namespace yang dideklarasikan?
Yisrael Dov
@YisraelDov Ya pasti kontra intuitif. Tapi untuk alasan apa pun itu berperilaku aneh dalam konteks ini. Terima kasih php
csga5000
@YisraelDov Saya kira itu karena dalam kasus itu instantiating kelas dari namespace lain akan sangat sakit kepala. Juga pertimbangkan bahwa variabel dapat diedarkan. Ketika classname ditulis sebagai teks ke dalam file php, siapa pun yang menulisnya tahu persis apa namespace itu ditulis. Tetapi ketika variabel dilewatkan di antara fungsi, itu akan menjadi mimpi buruk untuk menindaklanjutinya. Juga jika Anda menggunakan get_class () itu akan mengembalikan nama kelas FQ, sehingga dapat langsung disimpan dalam variabel dan digunakan di mana saja. Jika itu tergantung pada namespace file, itu tidak akan berfungsi dengan baik.
sbnc.eu
61

Cara melewati parameter konstruktor dinamis juga

Jika Anda ingin meneruskan parameter konstruktor dinamis ke kelas, Anda dapat menggunakan kode ini:

$reflectionClass = new ReflectionClass($className);

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

Informasi lebih lanjut tentang kelas dan parameter dinamis

PHP> = 5.6

Pada PHP 5.6 Anda dapat menyederhanakan ini lebih banyak lagi dengan menggunakan Argument Unpacking :

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

Terima kasih kepada DisgruntledGoat karena menunjukkannya.

flu
sumber
7
Dari PHP 5.6 Anda harus dapat menggunakan argumen unpacking:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
Zewew
sumber
Tidak, bukan contoh yang bagus. Hanya berfungsi jika semuanya ada dalam file php yang sama.
fralbo
2
2ndGAB harus menghapus komentar ini. Autoloading tidak ada hubungannya dengan pertanyaan ini.
Jim Maguire
-1

Saya akan merekomendasikan metode call_user_func()atau call_user_func_arrayphp. Anda dapat memeriksanya di sini ( call_user_func_array , call_user_func ).

contoh

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

Jika Anda memiliki argumen yang Anda sampaikan ke metode, maka gunakan call_user_func_array()fungsinya.

contoh.

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"));
pickman murimi
sumber
3
Jawaban ini tidak berlaku untuk pertanyaan. OP bertanya bagaimana MEMASANG kelas (memicu metode konstruksi kelas __ secara dinamis) dari string variabel dan mendapatkan kembali OBYEK KELAS dalam variabel baru - saran Anda akan mengembalikan NILAI dari metode class-> ([]) you ' menelepon kembali, bukan objek kelas jadi tidak berlaku untuk kasus ini. Lihat nilai pengembalian php.net/manual/en/function.call-user-func-array.php
ChrisN