1: <?php
2: /**
3: * Hard type support
4: * For when you absolutely want to know what you are getting
5: *
6: * @author Ashley Kitson <akitson@zf4.biz>
7: * @copyright Ashley Kitson, UK, 2012
8: * @licence GPL V3 or later : http://www.gnu.org/licenses/gpl.html
9: */
10:
11: namespace chippyash\Type;
12:
13: /**
14: * An abstract type that has >1 intrinsic values
15: */
16: abstract class AbstractMultiValueType extends AbstractType
17: {
18: /**
19: * Values of the type
20: *
21: * @var array
22: */
23: protected $value = array();
24:
25: /**
26: * Map of value names to $value array position
27: * [pos=>[name, class], ...]
28: * You need to override this in child classes and set it
29: *
30: * `pos` refers to the order in which it is expected to be placed in the
31: * parameter list in constructor and set methods
32: *
33: * name is the name of the value
34: *
35: * class is the full class name of the expected value object
36: *
37: * @var array
38: */
39: protected $valueMap = array();
40:
41: /**
42: * Constructor
43: * This is variant parameter constructor. The type and number of arguments
44: * are determined by the value map
45: *
46: * @override
47: */
48: public function __construct()
49: {
50: $this->setFromTypes(func_get_args());
51: }
52:
53: /**
54: * Magic method - convert to string
55: * You MUST override this in your child class
56: *
57: * @abstract
58: * @return string
59: */
60: public function __toString()
61: {
62: return '';
63: }
64:
65: /**
66: * Get the value of the object typed properly as PHP Native type
67: *
68: * @return mixed
69: */
70: public function get()
71: {
72: return $this->getAsNativeType();
73: }
74:
75: /**
76: * This is variant parameter method. The type and number of arguments
77: * are determined by the value map
78: *
79: * @param mixed $value ignored
80: *
81: * @return \chippyash\Type\AbstractType Fluent Interface
82: */
83: public function set($value)
84: {
85: $this->setFromTypes(func_get_args());
86:
87: return $this;
88: }
89:
90: /**
91: * Magic clone method
92: * Ensure value gets cloned when object is cloned
93: *
94: * @return void
95: */
96: public function __clone()
97: {
98: foreach ($this->value as &$v) {
99: if (is_object($v)) {
100: $v = clone $v;
101: } //else $v has already been copied
102: }
103: }
104:
105: /**
106: * Magic invoke method
107: * Proxy to get()
108: *
109: * @see get
110: *
111: * @return mixed
112: */
113: public function __invoke()
114: {
115: return $this->get();
116: }
117:
118: /**
119: * Return multi value as native PHP type
120: *
121: * @return mixed
122: */
123: abstract protected function getAsNativeType();
124:
125: /**
126: * Not defined for multi value types
127: *
128: * @param mixed $value ignored
129: *
130: * @return void
131: *
132: * @throws \BadMethodCallException
133: */
134: final protected function typeOf($value)
135: {
136: throw new \BadMethodCallException('typeOf() method not defined for AbstractMultiValueType');
137: }
138:
139: /**
140: * Maps values passed in as parameters to constructor and set methods into
141: * the value array
142: *
143: * @param array $params
144: *
145: * @return void
146: *
147: * @throws \InvalidArgumentException
148: */
149: protected function setFromTypes(array $params)
150: {
151: if (count($params) != count($this->valueMap)) {
152: $numParams = count($params);
153: $expectedParams = count($this->valueMap);
154: throw new \InvalidArgumentException("Expected {$expectedParams} parameters, got {$numParams}");
155: }
156:
157: foreach ($params as $key => $value) {
158: if (is_object($value)) {
159: if (!$value instanceof $this->valueMap[$key]['class']) {
160: $c = get_class($value);
161: throw new \InvalidArgumentException("Invalid Type ({$c}) at position {$key}");
162: }
163: $this->value[$this->valueMap[$key]['name']] = clone $value;
164: } else {
165: $t = gettype($value);
166: if ($t != $this->valueMap[$key]['class']) {
167: throw new \InvalidArgumentException("Invalid Type ({$t}) at position {$key}");
168: }
169: $this->value[$this->valueMap[$key]['name']] = $value;
170: }
171:
172:
173: }
174:
175: }
176: }
177: