Object ->toArray() conversion in php

Viewed 12926

I want to cast a Object to an array, so i can iterate with an loop over it.
I know that:

$array = (array) $object 

exists. But I want something like the custom

__toString() 

method for arrays.
I know so far that

__toArray()

does not exist.
Question:
Can I create this magic method customly and how?
(I'm also aware of the fact, that i could work around this by just calling a function that returns an array)

I want to cast the Object to an custom array:

foreach($object as $key=>$value) {}

not converting it by calling a function

foreach($object->toArray as $key=>$value){}

even if it would be the simplest way ...

3 Answers

This is pretty easy. Just use get_object_vars()

https://secure.php.net/manual/en/function.get-object-vars.php

<?php

class Person
{
    private $name = 'delboy1978uk';
    private $age = 40;

    public function toArray()
    {
        return get_object_vars($this);
    }
}


$person = new Person();
var_dump($person->toArray());

Which gives you:

array(2) { ["name"]=> string(12) "delboy1978uk" ["age"]=> int(40) }

See here: https://3v4l.org/1TWrG

Now, suppose you want it in several classes. You can either create a base class and extend it, or make it a trait:

<?php

class ArrayableObject
{
    public function toArray()
    {
        return get_object_vars($this);
    }
}

class Person extends ArrayableObject
{
    private $name = 'delboy1978uk';
    private $age = 40;
}

In my opinion, it's more flexible if you use it in a trait, then you aren't tied to the base class:

<?php    

trait CastableToArray
{
    public function toArray()
    {
        return get_object_vars($this);
    }
}

class Person
{
    use CastableToArray;

    private $name = 'delboy1978uk';
    private $age = 40;
}

I had a problem, but I had nested classes, and the simple solution in this thread didn't work for me, so I wrote my own solution.

I have a trait and interface for my models

trait toArrayTrait
{

    /**
     * @return array
     */
    public function toArray(): array
    {
        $values = [];
        foreach ($this as $name => $var){
            $values[$name] = is_object($var) ? $var->toArray() : $var;
        }
        return $values;
    }

}


interface ToArrayAccess
{
    public function toArray();
}

And I have several models that implement and use the code posted above

class Offer implements ToArrayAccess
{
    use toArrayTrait;

    /**
     * @var
     */
    private $id;
    /**
     * @var
     */
    private $type;
    /**
     * @var
     */
    private $createdAt;
    /**
     * @var
     */
    private $updatedAt;
    /**
     * @var
     */
    private $expireAt;
    /**
     * @var
     */
    private $price;
    /**
     * @var
     */
    private $businessPrice;
    /**
     * @var
     */
    private $visibility;
    /**
     * @var
     */
    private $status;
    /**
     * @var Inventory
     */
    private $inventory;
    /**
     * @var Product
     */
    private $product;


    /**
     * Offer constructor.
     * @param $offer
     */
    public function __construct(stdClass $offer)
    {

        $this->id = $offer->id;
        $this->type = $offer->type;
        $this->createdAt = $offer->createdAt;
        $this->updatedAt = $offer->updatedAt;
        $this->expireAt = $offer->expireAt;
        $this->price = $offer->price;
        $this->businessPrice = $offer->businessPrice;
        $this->visibility = $offer->visibility;
        $this->status = $offer->status;
        $this->inventory = new Inventory($offer->inventory);
        $this->product = new Product($offer->product);

    }

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @return mixed
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * @return mixed
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    /**
     * @return mixed
     */
    public function getExpireAt()
    {
        return $this->expireAt;
    }

    /**
     * @return mixed
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * @return mixed
     */
    public function getBusinessPrice()
    {
        return $this->businessPrice;
    }

    /**
     * @return mixed
     */
    public function getVisibility()
    {
        return $this->visibility;
    }

    /**
     * @return mixed
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * @return Inventory
     */
    public function getInventory(): Inventory
    {
        return $this->inventory;
    }

    /**
     * @return Product
     */
    public function getProduct(): Product
    {
        return $this->product;
    }

}

As you can see, I have nested classes

class Inventory implements ToArrayAccess
{
    use toArrayTrait;

    /**
     * @var
     */
    private $size;
    /**
     * @var
     */
    private $sold;
    /**
     * @var
     */
    private $type;

    public function __construct(stdClass $inventory)
    {
        $this->size = $inventory->size;
        $this->sold = $inventory->sold;
        $this->type = $inventory->type;
    }

    /**
     * @return mixed
     */
    public function getSize()
    {
        return $this->size;
    }

    /**
     * @return mixed
     */
    public function getSold()
    {
        return $this->sold;
    }

    /**
     * @return mixed
     */
    public function getType()
    {
        return $this->type;
    }

}

And last class

class Product implements ToArrayAccess
{
    use toArrayTrait;

    /**
     * @var
     */
    private $id;
    /**
     * @var
     */
    private $name;
    /**
     * @var
     */
    private $sku;

    public function __construct(stdClass $product)
    {

        $this->id = $product->id;
        $this->name = $product->name;
        $this->sku = $product->sku;

    }

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return mixed
     */
    public function getSku()
    {
        return $this->sku;
    }

}

Before use function "toArray"

After use function "toArray"

Have you considered using ArrayObject?

<?php

class Myclass extends ArrayObject
{
    public function __construct(array $input = [])
    {
        parent::__construct($input);
    }
}

$object = new Myclass(['foo', 'bar', 'baz']);

foreach($object as $value) {
    echo $value . "\n";
}

// Outputs "foo bar baz" 
Related