Подтвердить что ты не робот

Как создавать объекты в PHP

У меня есть несколько классов, которые имеют некоторые атрибуты, и я хотел бы сделать что-то вроде:

$dog = (Dog) $cat;

это возможно или есть какая-то общая работа вокруг?

Это не суперкласс, не интерфейс и не связаны каким-либо образом. Это всего лишь два разных класса, я хотел бы, чтобы php отобразил атрибуты из класса cat в собаку и дал мне новый объект. -

Я думаю, мне нужно указать немного больше причин, кажется, бессмысленная вещь.

у меня есть классы, которые наследуются от разных родительских классов, потому что я создал дерево наследования на основе метода сохранения, может быть, мой плохой с самого начала, но проблема в том, что у меня есть много классов, которые практически равны, но взаимодействуют с MySQL и другой с файлами XML. так что я:

class MySql_SomeEntity extends SomeMysqlInteract{}

а также

Xml_SomeEntity extends SomeXmlInteract{}

его немного глубже дерево, но проблема в том, что. я не могу заставить их наследовать от одного и того же класса, потому что множественное наследование не разрешено, и я не могу отделить текущее взаимодействие с суперклазами, потому что это будет большой проблемой.

По сути, атрибуты в каждом из них практически одинаковы.

Так как у меня есть много подходящих классов, я хотел бы сделать общее преобразование или что-то подобное, которое может преобразовывать (передавать значения каждому атрибуту), но я пытаюсь найти самый простой способ для каждого из этих классов.

4b9b3361

Ответ 1

В PHP нет встроенного метода для персонализации типов объектов, определенных пользователем. Тем не менее, есть несколько возможных решений:

1) Используйте функцию, подобную приведенной ниже, для десериализации объекта, измените строку так, чтобы нужные вам свойства были включены в новый объект после десериализации.

function cast($obj, $to_class) {
  if(class_exists($to_class)) {
    $obj_in = serialize($obj);
    $obj_out = 'O:' . strlen($to_class) . ':"' . $to_class . '":' . substr($obj_in, $obj_in[2] + 7);
    return unserialize($obj_out);
  }
  else
    return false;
}

2) В качестве альтернативы вы можете скопировать свойства объекта с помощью отражения/вручную итерации через них всех или с помощью get_object_vars().

Эта статья должна рассказать вам о "темных углах PHP" и реализовать типизацию на уровне пользователя.

Ответ 2

Вы можете использовать вышеприведенную функцию для отливки не похожих объектов класса (PHP >= 5.3)

/**
 * Class casting
 *
 * @param string|object $destination
 * @param object $sourceObject
 * @return object
 */
function cast($destination, $sourceObject)
{
    if (is_string($destination)) {
        $destination = new $destination();
    }
    $sourceReflection = new ReflectionObject($sourceObject);
    $destinationReflection = new ReflectionObject($destination);
    $sourceProperties = $sourceReflection->getProperties();
    foreach ($sourceProperties as $sourceProperty) {
        $sourceProperty->setAccessible(true);
        $name = $sourceProperty->getName();
        $value = $sourceProperty->getValue($sourceObject);
        if ($destinationReflection->hasProperty($name)) {
            $propDest = $destinationReflection->getProperty($name);
            $propDest->setAccessible(true);
            $propDest->setValue($destination,$value);
        } else {
            $destination->$name = $value;
        }
    }
    return $destination;
}

Пример:

class A 
{
  private $_x;   
}

class B 
{
  public $_x;   
}

$a = new A();
$b = new B();

$x = cast('A',$b);
$x = cast('B',$a);

Ответ 3

Без использования наследования (как упомянутого автором), похоже, что вы ищете решение, которое может transform один класс к другому с preassumption разработчика знает и понимает сходство двух классов.

Нет никакого существующего решения для преобразования между объектами. Что вы можете попробовать:

Ответ 4

Похоже, что вы действительно хотите реализовать interface.

В вашем интерфейсе будут указаны методы, которые может обрабатывать объект, и когда вы передаете объект, реализующий интерфейс, методу, который хочет объект, поддерживающий интерфейс, просто введите аргумент с именем интерфейса.

Ответ 5

Вам не нужно кастинг. Все динамично.

У меня есть скидка класса.
У меня есть несколько классов, которые расширяют этот класс:
ProductDiscount
StoreDiscount
ShippingDiscount
...

Где-то в коде есть:

$pd = new ProductDiscount();
$pd->setDiscount(5, ProductDiscount::PRODUCT_DISCOUNT_PERCENT);
$pd->setProductId(1);

$this->discounts[] = $pd;

.....

$sd = new StoreDiscount();
$sd->setDiscount(5, StoreDiscount::STORE_DISCOUNT_PERCENT);
$sd->setStoreId(1);

$this->discounts[] = $sd;

И где-нибудь я:

foreach ($this->discounts as $discount){

    if ($discount->getDiscountType()==Discount::DISCOUNT_TYPE_PRODUCT){

        $productDiscount = $discount; // you do not need casting.
        $amount = $productDiscount->getDiscountAmount($this->getItemTotalPrice());
        ...
    }

}// foreach

Где getDiscountAmount является специальной функцией ProductDiscount, а функция getDiscountType является функцией скидок.

Ответ 6

лучший aproach:

class Animal
{
    private $_name = null;

    public function __construct($name = null)
    {
        $this->_name = $name;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        if ($to instanceof Animal) {
            $to->_name = $this->_name;
        } else {
            throw(new Exception('cant cast ' . get_class($this) . ' to ' . get_class($to)));
        return $to;
    }

    public function getName()
    {
        return $this->_name;
    }
}

class Cat extends Animal
{
    private $_preferedKindOfFish = null;

    public function __construct($name = null, $preferedKindOfFish = null)
    {
        parent::__construct($name);
        $this->_preferedKindOfFish = $preferedKindOfFish;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        parent::cast($to);
        if ($to instanceof Cat) {
            $to->_preferedKindOfFish = $this->_preferedKindOfFish;
        }
        return $to;
    }

    public function getPreferedKindOfFish()
    {
        return $this->_preferedKindOfFish;
    }
}

class Dog extends Animal
{
    private $_preferedKindOfCat = null;

    public function __construct($name = null, $preferedKindOfCat = null)
    {
        parent::__construct($name);
        $this->_preferedKindOfCat = $preferedKindOfCat;
    }

    /**
     * casts object
     * @param Animal $to
     * @return Animal
     */
    public function cast($to)
    {
        parent::cast($to);
        if ($to instanceof Dog) {
            $to->_preferedKindOfCat = $this->_preferedKindOfCat;
        }
        return $to;
    }

    public function getPreferedKindOfCat()
    {
        return $this->_preferedKindOfCat;
    }
}

$dogs = array(
    new Dog('snoopy', 'vegetarian'),
    new Dog('coyote', 'any'),
);

foreach ($dogs as $dog) {
    $cat = $dog->cast(new Cat());
    echo get_class($cat) . ' - ' . $cat->getName() . "\n";
}

Ответ 7

Если объект, из которого вы пытаетесь привести объект или к которому, имеет свойства, которые также являются пользовательскими классами, и вы не хотите проходить рефлексию, вы можете использовать это.

<?php
declare(strict_types=1);
namespace Your\Namespace\Here
{
  use Zend\Logger; // or your logging mechanism of choice
  final class OopFunctions
  {
    /**
     * @param object $from
     * @param object $to
     * @param Logger $logger
     *
     * @return object
     */
     static function Cast($from, $to, $logger)
    {
      $logger->debug($from);
      $fromSerialized = serialize($from);
      $fromName = get_class($from);
      $toName = get_class($to);
      $toSerialized = str_replace($fromName, $toName, $fromSerialized);
      $toSerialized = preg_replace("/O:\d*:\"([^\"]*)/", "O:" . strlen($toName) . ":\"$1", $toSerialized);
      $toSerialized = preg_replace_callback(
        "/s:\d*:\"[^\"]*\"/", 
        function ($matches)
        {
          $arr = explode(":", $matches[0]);
          $arr[1] = mb_strlen($arr[2]) - 2;
          return implode(":", $arr);
        }, 
        $toSerialized
      );
      $to = unserialize($toSerialized);
      $logger->debug($to);
      return $to;
    }
  }
}

Ответ 8

Вы можете думать о фабриках

class XyFactory {
    public function createXyObject ($other) {
        $new = new XyObject($other->someValue);
        // Do other things, that let $new look like $other (except the used class)
        return $new;
    }
}

В противном случае решение user250120s является единственным, которое приближается к классу.

Ответ 9

class It {
    public $a = '';

    public function __construct($a) {
        $this->a = $a;
    }
    public function printIt() {
        ;
    }
}

//contains static function to 'convert' instance of parent It to sub-class instance of Thing

class Thing extends it {
    public $b = '';

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }
    public function printThing() {
        echo $this->a . $this->b;
    }
        //static function housed by target class since trying to create an instance of Thing
    static function thingFromIt(It $it, $b) {
        return new Thing($it->a, $b);
    }
}


//create an instance of It
$it = new It('1');

//create an instance of Thing 
$thing = Thing::thingFromIt($it, '2');


echo 'Class for $it: ' . get_class($it);
echo 'Class for $thing: ' . get_class($thing);

Возврат:

Class for $it: It
Class for $thing: Thing

Ответ 10

Я думаю, что лучший подход - просто создать новый экземпляр класса и назначить объект. Вот что я буду делать:

public function ($someVO) {

     $someCastVO = new SomeVO();
     $someCastVO = $someVO;
     $someCastVO->SomePropertyInVO = "123";

}

Выполнение этого даст вам подсказку кода в большинстве IDE и поможет убедиться, что вы используете правильные свойства.