web-dev-qa-db-fra.com

Comment lancer des objets dans PHP

J'ai quelques classes qui partagent certains attributs, et j'aimerais faire quelque chose comme: $ Dog = (Dog) $ cat;

est-ce possible ou existe-t-il des solutions génériques?

Ce n'est pas une super-classe, ni une interface, ni aucun lien. Ils ne sont que 2 classes différentes. J'aimerais que php mappe les attributs d'une classe de chat à un chien et me donne le nouvel objet. -

je suppose que je dois spécifier un peu plus de cause parce que cela semble être une chose insensée à faire.

les classes ive qui héritent des familles différentes. ive a créé un arbre d’héritage basé sur la méthode de sauvegarde, peut-être ma mauvaise au début, mais le problème est que j’ai beaucoup de classes pratiquement égales mais qui interagissent l’un avec mysql et l’autre avec des fichiers XML. Ainsi, j'ai: class MySql_SomeEntity étend SomeMysqlInteract {} et Xml_SomeEntity étend SomeXmlInteract {} C'est un arbre un peu plus profond, mais le problème est que. Je ne peux pas leur faire hériter de la même classe parce que l'héritage multiple n'est pas autorisé, et je ne peux pas séparer les interactions actuelles avec les super-classes car la cause serait un gros problème.

Fondamentalement, les attributs de chacun sont pratiquement les mêmes.

depuis que j'ai beaucoup de ces classements, je voudrais faire un casting générique ou quelque chose de ce genre qui peut convertir (passe les valeurs à chaque attribut) et que je suis en train d'essayer de rechercher le moyen le plus simple pour tout le monde de ces classements. 

55
user267599

Il n'y a pas de méthode intégrée pour la conversion de types d'objets définis par l'utilisateur en PHP. Cela dit, voici plusieurs solutions possibles:

1) Utilisez une fonction telle que celle ci-dessous pour désérialiser l'objet, modifiez la chaîne de sorte que les propriétés nécessaires soient incluses dans le nouvel objet une fois qu'il est désérialisé.

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) Alternativement, vous pouvez copier les propriétés de l'objet en utilisant réflexion/itération manuelle à travers elles ou en utilisant get_object_vars ().

Cet article devrait vous éclairer sur les "coins sombres de PHP" et sur la mise en œuvre de la conversion au niveau utilisateur. 

30
user250120

Vous pouvez utiliser la fonction ci-dessus pour la conversion d'objets de classe non similaires (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;
}

EXEMPLE:

class A 
{
  private $_x;   
}

class B 
{
  public $_x;   
}

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

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

Sans utiliser l'héritage (tel que mentionné par l'auteur ), il semble que vous cherchiez une solution qui peut transform d'une classe à une autre avec une présomption du développeur connaissant et comprenant la similitude de 2 classes.

Il n'y a pas de solution existante pour transformer des objets. Ce que vous pouvez essayer sont:

3
Trav L

Cela ressemble à ce que vous voulez vraiment faire est de mettre en œuvre une interface .

Votre interface spécifiera les méthodes que l'objet peut gérer et lorsque vous transmettez un objet qui implémente l'interface à une méthode qui recherche un objet prenant en charge l'interface, vous tapez simplement l'argument avec le nom de l'interface.

2
Matthew Sturges

Si l'objet que vous essayez de convertir a ou a des propriétés qui sont aussi des classes définies par l'utilisateur et que vous ne souhaitez pas utiliser la réflexion, vous pouvez l'utiliser.

<?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;
    }
  }
}
1
Justin

une meilleure approche:

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";
}
1
useless

Vous n'avez pas besoin de casting. Tout est dynamique.

J'ai un rabais de classe.
J'ai plusieurs classes qui étend cette classe:
ProductDiscount
StoreDiscount
ShippingDiscount
... 

Quelque part dans le code j'ai:

$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;

Et quelque part j'ai: 

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

Où getDiscountAmount est une fonction spécifique à ProductDiscount et getDiscountType est une fonction spécifique à Discount.

1
darpet

Vous pouvez penser aux usines

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;
    }
}

Sinon, la solution user250120s est la seule à se rapprocher du casting de classe.

0
KingCrunch
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);

Résultats:

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

Je pense que la meilleure approche consiste simplement à créer une nouvelle instance d'une classe et à assigner l'objet. Voici ce que je ferais:

public function ($someVO) {

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

}

Cela vous donnera des indications de code dans la plupart des IDE et vous aidera à utiliser les propriétés correctes.

0
Elad Elrom