PHP Dinamik Değişkenler ile Nesneleri başlatmasını Etkileri

12 Cevap php

PHP yeni bir sınıf örneğini bildirmek için aşağıdaki formu kullanarak performans, güvenlik, ya da "diğer" etkileri nelerdir

<?php
    $class_name = 'SomeClassName';
    $object = new $class_name;
?>

Bu yapmacık bir örnektir, ama ben büyük bir if / switch deyimi önlemek için Fabrikalar (OOP) kullanılan bu formu gördüm.

Hemen akla geliyor Sorunları

  1. You lose the ability to pass arguments into a constructor (LIES. teşekkürler Jeremy)
  2. Tüm bu masaya getiriyor, güvenlik endişeleri ile,) (eval gibi kokuyor (ama ille performans kaygıları?)

Başka hangi etkileri vardır, ya da hangi arama motoru "Rank PHP hackery" dışında başka terimler birisi bu araştırma için kullanabilir miyim?

12 Cevap

Çalışma zamanında çözme ile konulardan biri size (APC) gibi opcode cache gerçekten zor hale olmasıdır. Yine de, şimdi, malzeme instanciating zaman yönlendirme belirli bir miktar ihtiyacınız varsa size söz açıklamak gibi geçerli bir yoldur şey yapıyor.

Sürece gibi bir şey yok gibi

$classname = 'SomeClassName';
for ($x = 0; $x < 100000; $x++){
  $object = new $classname;
}

Eğer muhtemelen iyi olan :-)

(Benim açımdan olmak: Dinamik burada bir sınıf yukarı bakıyor ve sonra zarar vermez sık sık yaparsanız, o olacak.).

Ayrıca, $ classname dışarıdan ayarlanabilir asla emin olun - Eğer başlatmasını olacak ne tam sınıfı üzerinde bir miktar kontrol etmek isterdim.

O hala kurucusuna argümanlar geçebilir görünüyor, burada benim test kodu:

<?php

class Test {
    function __construct($x) {
    	echo $x;
    }
}

$class = 'Test';
$object = new $class('test'); // echoes "test"

?>

Bu doğru, sen ne demek olduğunu?

Yani aklınıza yalnızca diğer Bahsettiğiniz sorun ve bunun güvenlik, ancak bunun güvenli hale getirmek için çok zor olmamalı, ve tabii ki çok daha güvenli eval kullanarak daha () bulunuyor.

Ben de kullanarak parametreleri dinamik dizi ile instanciate olduğunu eklemek istiyorum:

<?php

$class = "Test";
$args = array('a', 'b');
$ref = new ReflectionClass($class);
$instance = $ref->newInstanceArgs($args);

?>

Ama tabii bunu yaparken biraz daha yükü ekleyin.

Güvenlik sorunu hakkında ben en azından eval () göre hiçbir şey, çok önemli olduğunu sanmıyorum. Yanlış sınıf instanciated alır kötü durumda, tabii ki bu potansiyel bir güvenlik boşluğu olduğu sömürmek çok zor ve gerçekten sınıf adını tanımlamak için kullanıcı girişi gerekiyorsa bu, izin verilen sınıfları bir dizi kullanarak süzmek kolay.

Gerçekten sınıf tanımını ararken önce değişkenin adını çözümlemek zorunda için bir performans isabet olabilir. Ama, sınıfları bildirmek olmadan dinamik "dyanmic" veya "meta" programlama yapmak için gerçek bir yol var. Sen kod oluşturma programları veya bir etki alanına özgü dil yapı gibi bir şey yazmak mümkün olmaz.

Hepimiz dönüşümler işi kontrolör URL'yi yapmak bizim iç çerçevenin çekirdek sınıfların bazı yerde bu kuralı kullanabilirsiniz. Ben de (ben denemek ve bir örnek için kazmak ve onu göndeririz) birçok ticari açık kaynak kodlu uygulamalar gördük. Her neyse, benim cevap nokta o daha esnek, dinamik kod yaparsa muhtemelen hafif bir performans azalma ne de değer görünüyor olmasıdır.

Ben bahsetmeliyiz diğer ticaret-off olsa da, sizin değişken isimleri ile çok dikkatli olmadıkça kod biraz daha az belirgin ve okunabilir yapar, bunu bir kenara performans. En kodu bir kez yazılabilir ve yeniden okumak ve birçok kez değiştirilmiş, bu yüzden okunabilirliği önemli olduğunu.

Alan, dinamik sınıf başlatma ile yanlış bir şey yok. Bu teknik bir Class.forClass('classname') yöntemi kullanılarak sınıf dizeyi dönüştürmek Java dilinde de mevcut. Bunun yerine eğer-koşullar listesi olan çeşitli sınıflar için algoritma karmaşıklığı erteleme de oldukça kullanışlı. Dinamik sınıf isimleri, özellikle de sizin kodu değişiklikleri için gerek kalmadan uzantısı açık kalmasını istediğiniz durumlarda uygundur.

Kendimi genellikle veritabanı tabloları ile birlikte farklı sınıflarını kullanın. Bir sütunda ben kaydını işlemek için kullanılacak sınıf adı tutmak. Bu bana kayıtların yeni tip ekleyerek büyük bir güç veriyor ve mevcut kodu tek bir bayt değiştirmeden benzersiz şekilde onları ele.

Sen performansı endişe olmamalı. Neredeyse hiç tepegöz vardır ve kendilerini PHP süper hızlı nesneleri. Eğer, aynı nesneleri binlerce yumurtlamaya bellek ayak izini azaltmak için Flyweight tasarım deseni kullanmak gerekir. Özellikle, sadece sunucu üzerinde milisaniye kaydetmek için bir geliştirici olarak zaman feda edilmemelidir. Ayrıca op-kod optimisers bu tekniği ile sorunsuz çalışır. Zend Optimizer ile derlenmiş Script yaramazlık yoktu.

Yani son zamanlarda karşılaştığımız ve dinamik örnekleme kullanarak "diğer" etkileri üzerine düşüncelerimi vermek istedim.

Bir şey için func_get_args() şeylerin içine bir anahtarı biraz atar. Örneğin ben belirli bir sınıf için bir yapıcı (örneğin fabrika yöntemi) gibi davranan bir yöntem oluşturmak istiyorum. Ben başlatmasını ediyorum sınıfının kurucusuna benim fabrika yönteme geçirilen params iletmekten gerekiyor olurdu.

Eğer yaparsanız:

public function myFactoryMethod() 
{
  $class = 'SomeClass'; // e.g. you'd get this from a switch statement
  $obj = new $class( func_get_args() );
  return $obj;
}

ve sonra arayın:

$ Fabrika-> myFactoryMethod ('foo', 'bar');

Aslında new SomeClass( array( 'foo', 'bar' ) ) Bu bizim istediğimiz belli değil olduğu gibi aynı ilk / tek param gibi bir dizi geçiyoruz.

(@ Seldaek tarafından belirtildiği gibi) çözüm kurucu params içine dizi dönüştürmek için bize gerektirir:

public function myFactoryMethod() 
{
  $class = 'SomeClass'; // e.g. you'd get this from a switch statement
  $ref = new ReflectionClass( $class );
  $obj = $ref->newInstanceArgs( func_get_args() );
  return $obj;
}

Not: Eğer yeni nesneler örneğini oluşturmak için bu yaklaşımı kullanabilirsiniz, çünkü bu, call_user_func_array kullanılarak başarılı olamazdı.

HTH!

Ben sadece burada tahmin ediyorum, ama muhtemelen IDE kod tamamlama kırar.

Bir performans farkı için kıstas mı?

Benim özel çerçevesinde dinamik örnekleme kullanın. Benim uygulama denetleyici talebine dayalı bir alt-denetleyici örneğini gerekiyor ve bu kontrolörlerin yükleme yönetmek için bir dev, sürekli değişen anahtar deyimini kullanmak için basitçe saçma olurdu. Sonuç olarak, ben onları aramak için app denetleyicisi değiştirmek zorunda kalmadan benim uygulama denetleyicisi sonra denetleyicisi ekleyebilirsiniz. Sürece benim URI'larını benim çerçeve sözleşmelere uygun olarak, app kontrolör çalışma zamanı kadar hiçbir şey bilmek zorunda kalmadan kullanabilirsiniz.

Ben şu anda bir üretim alışveriş sepeti uygulaması bu çerçeveyi kullanıyorum ve performans da oldukça olumludur. Söyleniyor, ben sadece tüm app bir veya iki noktalar dinamik sınıf seçimi kullanıyorum. Ben sık sık kullanmak gerekir hangi koşullarda merak ve olsun veya olmasın bu durumlar aşırı soyut uygulama (daha önce bu suçlu oldum) bir programcının arzusu muzdarip olanlardır.

Bir sorun, örneğin, böyle statik üyelere hitap değil ki

<?php
$className = 'ClassName';

$className::someStaticMethod(); //doesn't work
?>

@ ColdFlame Bildiğim kadarıyla bu işe bildiği gibi PHP5.3 başlangıç

@ coldFlame: IIRC size call_user_func(array($className, 'someStaticMethod') kullanabilir ve call_user_func_array() params'ı geçmek

class Test {
    function testExt() {
    print 'hello from testExt :P';
    }
    function test2Ext()
    {
    print 'hi from test2Ext :)';
    }
}


$class = 'Test';
$method_1 = "testExt";
$method_2 = "test2Ext";
$object = new $class(); // echoes "test"
$object->{$method_2}(); // will print 'hi from test2Ext :)'
$object->{$method_1}(); // will print 'hello from testExt :P';

Bu hile PHP4 ve PHP5 hem de çalışıyor: D enjoy ..