TypedArray::__clone()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
rs 9.4285
ccs 4
cts 4
cp 1
cc 2
eloc 3
nc 2
nop 0
crap 2
1
<?php
2
3
namespace RQuadling\TypedArray;
4
5
/**
6
 * Class TypedArray.
7
 *
8
 * @todo Implement a 'clone by default' mechanism
9
 */
10
abstract class TypedArray extends \ArrayObject
11
{
12
    /**
13
     * Define the class that will be used for all items in the array.
14
     * To be defined in each sub-class.
15
     */
16
    const ARRAY_TYPE = null;
17
18
    /**
19
     * Define the type of element for the array.
20
     */
21
    private $arrayType;
22
23
    /**
24
     * TypedArray constructor.
25
     *
26
     * @param array|object $input          The input parameter accepts an array or an Object
27
     * @param int          $flags          Flags to control the behaviour of the ArrayObject object
28
     * @param string       $iterator_class Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used
29 15
     */
30
    public function __construct($input = [], $flags = 0, $iterator_class = 'ArrayIterator')
31
    {
32
        /*
33
         * Validate that the subclass has correctly defined an ARRAY_TYPE.
34 15
         */
35
        $this->arrayType = static::ARRAY_TYPE;
36 15
37 2
        if (empty($this->arrayType)) {
38 2
            throw new \RuntimeException(
39 2
                sprintf(
40 2
                    '%s::ARRAY_TYPE must be set to a valid class.',
41 2
                    get_called_class()
42 2
                )
43
            );
44
        }
45 13
46 1
        if (!class_exists($this->arrayType)) {
47 1
            throw new \RuntimeException(
48 1
                sprintf(
49 1
                    '%s does not exist for %s::ARRAY_TYPE',
50 1
                    $this->arrayType,
51 1
                    get_called_class()
52 1
                )
53
            );
54
        }
55
56
        /*
57
         * Validate that the input is an array or an object with an Traversable interface.
58 12
         */
59 2
        if (!(is_array($input) || (is_object($input) && in_array('Traversable', class_implements($input))))) {
60
            throw new \InvalidArgumentException('$input must be an array or an object that implements \Traversable.');
61
        }
62
63
        /*
64
         * Create an empty array.
65 10
         */
66
        parent::__construct([], $flags, $iterator_class);
67
68
        /*
69
         * Append each item so to validate it's type.
70 10
         */
71 7
        foreach ($input as $key => $value) {
72 9
            $this[$key] = $value;
73 9
        }
74
    }
75
76
    /**
77
     * Clone a collection by cloning all items.
78 1
     */
79
    public function __clone()
80 1
    {
81 1
        foreach ($this as $key => $value) {
82 1
            $this[$key] = clone $value;
83 1
        }
84
    }
85
86
    /**
87
     * Check the type and then store the value.
88
     *
89
     * @param int|null $offset The offset to store the value at or null to append the value
90
     * @param mixed    $value  The value to store
91 9
     */
92
    public function offsetSet($offset, $value)
93
    {
94
        /*
95
         * The value must be an object.
96 9
         */
97 3
        if (!is_object($value)) {
98 3
            throw new \InvalidArgumentException(
99 3
                sprintf(
100 3
                    "Non object of type '%s' supplied. Wanted object of type '%s'.",
101 3
                    gettype($value),
102 3
                    $this->arrayType
103 3
                )
104
            );
105
        }
106
107
        /**
108
         * The value must be an instance of the $this->arrayType.
109 7
         */
110 3
        if (!($value instanceof $this->arrayType)) {
111 3
            throw new \InvalidArgumentException(
112 3
                sprintf(
113 3
                    "Object of class '%s' supplied. Wanted object of type '%s'.",
114 3
                    get_class($value),
115 3
                    $this->arrayType
116 3
                )
117
            );
118
        }
119 5
120 5
        parent::offsetSet($offset, $value);
121
    }
122
}
123