PHP dinamik örnek özelliklerini oluşturabilir miyim?

10 Cevap php

Dinamik olarak tüm örnek özelliklerini oluşturmak için herhangi bir yolu var mı? Örneğin, ben sınıf böyle örneği sonra kurucudaki tüm özelliklerini elde edebilmek ve onlara hala erişmek mümkün istiyorum: $object->property. Ben ayrı ayrı özelliklere erişmek istediğiniz, ve bir dizi kullanarak değil, unutmayın; burada don't istediklerini bir örnek:

class Thing {
    public $properties;
    function __construct(array $props=array()) {
        $this->properties = $props;
    }
}
$foo = new Thing(array('bar' => 'baz');
# I don't want to have to do this:
$foo->properties['bar'];
# I want to do this:
//$foo->bar;

Ben özellikleri çok sayıda sınıfları ile uğraşırken, ben bir veritabanındaki tüm sütunları seçmek için muktedir gibi (özelliklerini temsil eden) ve onlardan örnek özelliklerini yaratacak, daha spesifik olmak gerekirse. Her sütun değeri, ayrı bir örnek özelliğinin saklanmalıdır.

10 Cevap

Sıralama. Eğer zamanında sınıf davranışı uygulamak kadar kendi kod kanca izin sihirli yöntem vardır:

class foo {
  public function __get($name) {
    return('dynamic!');
  }
  public function __set($name, $value) {
    $this->internalData[$name] = $value;
  }
}

Bu dinamik girişken ve ayarlayıcı yöntemleri için bir örnek, bir nesne özelliği her erişildiğinde size davranışı çalıştırmasına izin veriyor. Örneğin

print(new foo()->someProperty);

Bu durumda, "dinamik", yazdırmak istiyorum ve ayrıca __ set () yöntemi sessizce çağrıldığında bu durumda rasgele adlandırılmış bir özellik için bir değer atayabilirsiniz. __ Call ($ isim, $ params) yöntemi nesne yöntem çağrıları için aynı işi yapar. Özel durumlarda çok faydalıdır. Ama çoğu zaman, sizinle tarafından alırsınız:

class foo {
  public function __construct() {
    foreach(getSomeDataArray() as $k => $value)
      $this->{$k} = $value;
  }
}

... Çoğunlukla, tüm ihtiyacınız mukabil adında sınıf bir kez alanlar, ya da en azından icra yolu çok açık noktalarında içine bir dizinin içeriğini dökümü için çünkü. Eğer gerçekten dinamik davranışı gerek sürece Yani, son örnek veri ile nesneleri doldurmak için kullanabilirsiniz.

This is called overloading http://php.net/manual/en/language.oop5.overloading.php

Bu tam olarak ne istediğinizi bağlıdır. Dinamik class değiştirebilir miyim? Gerçekten değil. Ama o sınıfın belirli bir örneği olarak, dinamik object özellikleri oluşturabilirsiniz? Evet.

class Test
{
    public function __construct($x)
    {
        $this->{$x} = "dinamik";
    }
}

$a = new Test("bar");
print $a->bar;

Çıkışlar:

dinamik

So an object property named "bar" was created dinamikally in the constructor.

Evet, yapabilirsiniz.

class test
{
    public function __construct()
    {
    	$arr = array
    	(
    		'column1',
    		'column2',
    		'column3'
    	);

    	foreach ($arr as $key => $value)
    	{
    		$this->$value = '';
    	}	
    }

    public function __set($key, $value)
    {
    	$this->$key = $value;
    }

    public function __get($value)
    {
    	return 'This is __get magic '.$value;
    }
}

$test = new test;

// Results from our constructor test.
var_dump($test);

// Using __set
$test->new = 'variable';
var_dump($test);

// Using __get
print $test->hello;

Output

object(test)#1 (3) {
  ["column1"]=>
  string(0) ""
  ["column2"]=>
  string(0) ""
  ["column3"]=>
  string(0) ""
}
object(test)#1 (4) {
  ["column1"]=>
  string(0) ""
  ["column2"]=>
  string(0) ""
  ["column3"]=>
  string(0) ""
  ["new"]=>
  string(8) "variable"
}
This is __get magic hello

Bu kod, $ this-> sütunu ile ulaşılabilir kurucusuna dinamik özelliklerini koyacaktır. Aynı kullanmak da iyi bir uygulama __ almak ve __ sınıf içinde tanımlanmış değildir özellikleri ile başa çıkmak için sihirli yöntemleri ayarlayabilirsiniz. Daha fazla bilgi için onları burada bulabilirsiniz.

http://www.tuxradar.com/practicalphp/6/14/2

http://www.tuxradar.com/practicalphp/6/14/3

Sen keyfi değerleri için bir tutucu olarak hareket etmek bir örnek değişkeni kullanabilir ve daha sonra kullanabilirsiniz __ düzenli özellikleri olarak almak için sihirli bir yöntem olsun:

class My_Class
{
    private $_properties = array();

    public function __construct(Array $hash)
    {
         $this->_properties = $hash;
    }

    public function __get($name)
    {
         if (array_key_exists($name, $this->_properties)) {
             return $this->_properties[$name];
         }
         return null;
    }
}

Neden her örnek bu kadar karmaşık?

<?php namespace example;

\error_reporting(E_ALL | E_STRICT);

class Foo
{
    // completely empty
}

$testcase = new Foo();
$testcase->example = 'Dynamic property';
echo $testcase->example;

Stdclass uzatın.

class MyClass extends stdClass
{
    public function __construct()
    {
        $this->prop=1;
    }
}

Bu ne ihtiyaç vardır umarım.

Şunları yapabilirsiniz:

$variable = 'foo';
$this->$variable = 'bar';

foo o bar üzerine denir nesnenin niteliğini ayarlarsınız.

Ayrıca işlevlerini kullanabilirsiniz:

$this->{strtolower('FOO')} = 'bar';

Bu aynı zamanda foo (değil FOO) bar olarak ayarlanmış olur.

İşte bu yaklaşım bir örnek:

class User
{
    var $id;
    var $role;

    public function __construct($id)
    {
        if ($id)
        {
            $this->id = $id;
            $this->get();
        }
    }

    function isAdmin()
    {
        return $this->role == 'admin' ? TRUE : FALSE ;
    }

    private function get()
    {
        if ($this->id)
        {
            $query =
            "
                SELECT *
                FROM users
                WHERE user_id='$this->id'
            ";

            // do query, check for error
            $result = @mysql_query($query);
            if ($result)
            {
                $row = @mysql_fetch_assoc($result);
                if ($row)
                {
                    foreach ($row as $i => $v)
                    {
                        // rewrite user_[id|hash] field names
                        $i = str_replace("user_","",$i);

                        // set properties
                        $this->$i = $v;
                    }

                    @mysql_free_result($result);

                    return $row;
                }
            }
        }

        return FALSE;
    }
}

Aşağıdaki gibi olsun işlevi dinamik özellikleri temelde atanır:

foreach ($row as $i => $v)
{
	// rewrite user_[id|hash] field names
	$i = str_replace("user_","",$i);

	// set properties
	$this->$i = $v;
}

Ayrıca ben bir IsAdmin yöntemi olduğunu fark ve ben yukarıda beyan olması gerekir "rol" özelliğini kullanın çünkü, $ this-rol özelliğini kullanın.

Bu gerçekten hızlı bir gelişme bu tür işlemek için karmaşık bir yoludur. Ben cevapları ve sihirli yöntemler gibi ama bence CodeSmith gibi kod jeneratörler kullanmak daha iyidir.

Ben veritabanına bağlanmak şablonu, tüm sütunları ve veri türlerini okuyabilir ve buna göre bütün sınıf oluşturmak yaptık.

Bu şekilde ben okunabilir kod (hiçbir yazım) hatası ücretsiz var. Veritabanı modeli değişiklikleri yeniden jeneratör çalıştırmak ve eğer ... o benim için çalışıyor.

Eğer gerçekten bunu yapmak gerekir, en iyi yolu yineleme desteği (foreach) korumak için sağlayan bir ArrayObject, aşırı olduğunu olacak hala tüm özelliklerini döngü.

Sana "bir dizi kullanmadan" dedi unutmayın, ve ben sadece bu süre technically bir dizi arka planda kullanılan ediliyor, bunu görmek zorunda asla sizi temin etmek istiyorum. > Properyname veya foreach ($ isim => $ $ değerine sınıf) - Sen ile tüm özelliklerine erişebilirsiniz.

İşte dün üzerinde çalışan bir örnek, bu da ŞİDDETLE Yazılan unutmayınız. Eğer denemek ve bir "dize" tedarik Yani işaretlenmiştir özellikleri "tamsayı" bir hata atmak olacaktır.

Bunu tabii ki kaldırabilirsiniz.

Bu örnekte gösterildiği olmamakla birlikte bir AddProperty () üye işlevi de bulunmaktadır. Bu daha sonra özellikleri eklemek için izin verecektir.

Örnek kullanım:

    $Action = new StronglyTypedDynamicObject("Action",
            new StrongProperty("Player", "ActionPlayer"),   // ActionPlayer
            new StrongProperty("pos", "integer"),
            new StrongProperty("type", "integer"),
            new StrongProperty("amount", "double"),
            new StrongProperty("toCall", "double"));

    $ActionPlayer = new StronglyTypedDynamicObject("ActionPlayer",
            new StrongProperty("Seat", "integer"),
            new StrongProperty("BankRoll", "double"),
            new StrongProperty("Name", "string"));

    $ActionPlayer->Seat = 1;
    $ActionPlayer->Name = "Doctor Phil";

    $Action->pos = 2;
    $Action->type = 1;
    $Action->amount = 7.0;
    $Action->Player = $ActionPlayer;

    $newAction = $Action->factory();
    $newAction->pos = 4;

    print_r($Action);
    print_r($newAction);


    class StrongProperty {
            var $value;
            var $type;
            function __construct($name, $type) {
                    $this->name = $name;
                    $this->type = $type;
            }

    }

    class StronglyTypedDynamicObject extends ModifiedStrictArrayObject {

            static $basic_types = array(
                    "boolean",
                    "integer",
                    "double",
                    "string",
                    "array",
                    "object",
                    "resource",
            );

            var $properties = array(
                    "__objectName" => "string"
            );

            function __construct($objectName /*, [ new StrongProperty("name", "string"), [ new StrongProperty("name", "string"), [ ... ]]] */) {
                    $this->__objectName = $objectName;
                    $args = func_get_args();
                    array_shift($args);
                    foreach ($args as $arg) {
                            if ($arg instanceof StrongProperty) {
                                    $this->AddProperty($arg->name, $arg->type);
                            } else {
                                    throw new Exception("Invalid Argument");
                            }
                    }
            }

            function factory() {
                    $new = clone $this;
                    foreach ($new as $key => $value) {
                            if ($key != "__objectName") {
                                    unset($new[$key]);
                            }
                    }

                    // $new->__objectName = $this->__objectName;
                    return $new;
            }

            function AddProperty($name, $type) {
                    $this->properties[$name] = $type;
                    return;

                    if (in_array($short_type, self::$basic_types)) {
                            $this->properties[$name] = $type;
                    } else {
                            throw new Exception("Invalid Type: $type");
                    }
            }

            public function __set($name, $value) {
                    self::sdprintf("%s(%s)\n", __FUNCTION__, $name);
                    $this->check($name, $value);
                    $this->offsetSet($name, $value);
            }

            public function __get($name) {
                    self::sdprintf("%s(%s)\n", __FUNCTION__, $name);
                    $this->check($name);
                    return $this->offsetGet($name);
            }

            protected function check($name, $value = "r4nd0m") {
                    if (!array_key_exists($name, $this->properties)) {
                            throw new Exception("Attempt to access non-existent property '$name'");
                    }

                    $value__objectName = "";
                    if ($value != "r4nd0m") {
                            if ($value instanceof StronglyTypedDynamicObject) {
                                    $value__objectName = $value->__objectName;
                            }
                            if (gettype($value) != $this->properties[$name] && $value__objectName != $this->properties[$name]) { 
                                    throw new Exception("Attempt to set {$name} ({$this->properties[$name]}) with type " . gettype($value) . ".$value__objectName");
                            }
                    }
            }
    }

    class ModifiedStrictArrayObject extends ArrayObject {
            static $debugLevel = 0;

            /* Some example properties */

            static public function StaticDebug($message) {
                    if (static::$debugLevel > 1) {
                            fprintf(STDERR, "%s\n", trim($message));
                    }
            }

            static public function sdprintf() {
                    $args = func_get_args();
                    $string = call_user_func_array("sprintf", $args);
                    self::StaticDebug("D            " . trim($string));
            }

            protected function check($name) {
                    if (!array_key_exists($name, $this->properties)) {
                            throw new Exception("Attempt to access non-existent property '$name'");
                    }
            }

            //static public function sget($name, $default = NULL) {
            /******/ public function get ($name, $default = NULL) {
                    self::sdprintf("%s(%s)\n", __FUNCTION__, $name);
                    $this->check($name);
                    if (array_key_exists($name, $this->storage)) {
                            return $this->storage[$name];
                    }
                    return $default;
            }

            public function offsetGet($name) { 
                    self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
                    $this->check($name);
                    return call_user_func_array(array(parent, __FUNCTION__), func_get_args());
            }
            public function offsetSet($name, $value) { 
                    self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
                    $this->check($name);
                    return call_user_func_array(array(parent, __FUNCTION__), func_get_args());
            }
            public function offsetExists($name) { 
                    self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
                    $this->check($name);
                    return call_user_func_array(array(parent, __FUNCTION__), func_get_args());
            }
            public function offsetUnset($name) { 
                    self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
                    $this->check($name);
                    return call_user_func_array(array(parent, __FUNCTION__), func_get_args());
            }

            public function __toString() {
                    self::sdprintf("%s(%s)\n", __FUNCTION__, $name);
                    foreach ($this as $key => $value) {
                            $output .= "$key: $value\n";
                    }
                    return $output;
            }

            function __construct($array = false, $flags = 0, $iterator_class = "ArrayIterator") { 
                    self::sdprintf("%s(%s)\n", __FUNCTION__, implode(",", func_get_args()));
                    parent::setFlags(parent::ARRAY_AS_PROPS);
            }
    }