Issues (94)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

math/Vector.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace nyx\utils\math;
2
3
// External dependencies
4
use nyx\diagnostics;
5
6
/**
7
 * Vector
8
 *
9
 * Represents an immutable Euclidean vector of n dimensions with floating point precision.
10
 *
11
 * Note: Not using SplFixedArray internally despite always having a known array length since the possible
12
 *       performance/memory benefit would only materialize with a Vector of several thousand dimensions.
13
 *
14
 * @package     Nyx\Utils\Math
15
 * @version     0.1.0
16
 * @author      Michal Chojnacki <[email protected]>
17
 * @copyright   2012-2016 Nyx Dev Team
18
 * @link        http://docs.muyo.io/nyx/utils/math.html
19
 * @todo        Make Vectors actually mutable depending on use cases (considerable overhead per-tick currently)?
20
 */
21
class Vector implements \ArrayAccess
22
{
23
    /**
24
     * Distance type constants.
25
     */
26
    const DISTANCE_CARTESIAN   = 1;
27
    const DISTANCE_TAXICAB     = 2; // AKA Manhattan / city block / rectilinear distance
28
    const DISTANCE_MANHATTAN   = 2; // same as above
29
    const DISTANCE_CHEBYSHEV   = 3; // AKA chessboard distance
30
    const DISTANCE_CHESSBOARD  = 3; // same as above
31
32
    /**
33
     * @var int         The default distance type returned by the shorthand Vector::distanceTo() method. Kept
34
     *                  static and public on purpose since this is a utility setting for a utility method.
35
     */
36
    public static $defaultDistanceType = self::DISTANCE_CARTESIAN;
37
38
    /**
39
     * @var float[]     The components of the Vector.
40
     */
41
    protected $components;
42
43
    /**
44
     * Creates a zero-length vector of the given dimension.
45
     *
46
     * @param   int     $dimension          The dimension of the Vector to create. Must be >= 0.
47
     * @return  Vector                      A zero-length vector of the given dimension.
48
     * @throws  \InvalidArgumentException   When $dimension is less than 0.
49
     */
50
    public static function zero(int $dimension = 0) : Vector
51
    {
52
        if ($dimension === 0) {
53
            return new static([]);
54
        }
55
56
        if ($dimension < 0) {
57
            throw new \InvalidArgumentException('Expected dimension to be at least 0, got ['.$dimension.'] instead.');
58
        }
59
60
        return new static(array_fill(0, $dimension, 0));
61
    }
62
63
    /**
64
     * Creates a Vector of the appropriate type for the given $components.
65
     *
66
     * @param   array   $components         The components of the Vector. All values must be integers or floats ordered
67
     *                                      numerically (the order of the keys determines the order of dimensions,
68
     *                                      which becomes relevant in the 2D/3D vector implementations where they are
69
     *                                      named X/Y/Z).
70
     * @return  Vector                      A Vector type specific to the components given.
71
     */
72
    public static function from(array $components) : Vector
73
    {
74
        $dimensions = count($components);
75
76
        // Ordered by most common use cases.
77
        if ($dimensions === 3) {
78
            return new vectors\Vector3D((float) $components[0], (float) $components[1], (float) $components[2]);
79
        }
80
81
        if ($dimensions === 2) {
82
            return new vectors\Vector2D((float) $components[0], (float) $components[1]);
83
        }
84
85
        return new Vector($components);
86
    }
87
88
    /**
89
     * Constructs a new n-dimensional Vector.
90
     *
91
     * @param   float[] $components         The components of the Vector. All values must be numeric and will
92
     *                                      be cast to floats.
93
     * @throws  \InvalidArgumentException   When any of the components is not a numeric value.
94
     */
95
    public function __construct(array $components)
96
    {
97
        // Validate all components and cast them to floats.
98
        foreach ($components as $d => &$component) {
99
            if (!is_numeric($component)) {
100
                throw new \InvalidArgumentException('The value of the component ['.$d.'] is not numeric.');
101
            }
102
103
            $component = (float) $component;
104
        }
105
106
        $this->components = $components;
107
    }
108
109
    /**
110
     * Returns the absolute value of this Vector as a new Vector instance.
111
     *
112
     * @return  Vector
113
     */
114 View Code Duplication
    public function abs() : Vector
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        $result = [];
117
118
        foreach ($this->components as $i => $component) {
119
            $result[$i] = abs($component);
120
        }
121
122
        return new static($result);
123
    }
124
125
    /**
126
     * Returns the smallest of the components compared as absolute values. This is *not* the
127
     * absolute minimum (@see Vector::min() for that).
128
     *
129
     * @return  float
130
     */
131 View Code Duplication
    public function absMin() : float
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
    {
133
        $result = 0.0;
134
135
        foreach ($this->components as $component) {
136
            if ($result > $abs = abs($component)) {
137
                $result = $abs;
138
            }
139
        }
140
141
        return $result;
142
    }
143
144
    /**
145
     * Returns the biggest of the components compared as absolute values. This is *not* the
146
     * absolute maximum (@see Vector::max() for that).
147
     *
148
     * @return  float
149
     */
150 View Code Duplication
    public function absMax() : float
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
    {
152
        $result = 0.0;
153
154
        foreach ($this->components as $component) {
155
            if ($result < $abs = abs($component)) {
156
                $result = $abs;
157
            }
158
        }
159
160
        return $result;
161
    }
162
163
    /**
164
     * Adds $that Vector/number to this Vector and returns the result as a new Vector.
165
     *
166
     * @param   Vector|number    $that      The Vector or (numeric) bias to add to this Vector.
167
     * @return  Vector                      The sum of the two vectors.
168
     * @throws  \DomainException            When a Vector is given as input and it is not in the same space.
169
     * @throws  \InvalidArgumentException   When the value to add is neither a Vector nor numeric.
170
     */
171
    public function add($that) : Vector
172
    {
173
        $result = [];
174
175
        if ($that instanceof Vector) {
176
            if (!$this->isSameDimension($that)) {
177
                throw new \DomainException('The given input Vector is not in the same dimension as this Vector.');
178
            }
179
180
            foreach ($this->components as $i => $component) {
181
                $result[$i] = $component + $that->components[$i];
182
            }
183 View Code Duplication
        } elseif (is_numeric($that)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
            // We're accepting all numeric values but will be casting to a float, so be aware of potential
185
            // precision loss.
186
            $that = (float) $that;
187
188
            foreach ($this->components as $i => $component) {
189
                $result[$i] = $component + $that;
190
            }
191
        } else {
192
            throw new \InvalidArgumentException('Unknown type to add given - can only add other Vectors or numbers to Vectors.');
193
        }
194
195
        return new static($result);
196
    }
197
198
    /**
199
     * Returns the angle between this and $that Vector.
200
     *
201
     * @param   Vector   $that              The Vector to compute the angle between.
202
     * @return  float                       The angle between the Vectors, in radians.
203
     * @throws  \DomainException            When the given Vector is not in the same space as this Vector.
204
     * @throws  exceptions\DivisionByZero   When either of the Vectors is of zero length.
205
     */
206
    public function angleBetween(Vector $that)
207
    {
208
        if (!$this->isSameDimension($that)) {
209
            throw new \DomainException('The given Vector is not in the same dimension as this Vector.');
210
        }
211
212
        $denominator = $this->length() * $that->length();
213
214
        if ($denominator === 0) {
215
            throw new exceptions\DivisionByZero;
216
        }
217
218
        return acos($this->dotProduct($that) / $denominator);
219
    }
220
221
    /**
222
     * Computes the dot product of two Vectors (A | B).
223
     *
224
     * @param   Vector  $that       The Vector to compute the dot product against.
225
     * @return  float               The dot product of the two Vectors.
226
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
227
     */
228
    public function dotProduct(Vector $that) : float
229
    {
230
        if (!$this->isSameDimension($that)) {
231
            throw new \DomainException('The given Vector is not in the same dimension as this Vector.');
232
        }
233
234
        $result = 0;
235
236
        foreach ($this->components as $i => $component) {
237
            $result += $component * $that->components[$i];
238
        }
239
240
        return (float) $result;
241
    }
242
243
    /**
244
     * Returns the components of the Vector.
245
     *
246
     * @return  float[]
247
     */
248
    public function components() : array
249
    {
250
        return $this->components;
251
    }
252
253
    /**
254
     * Returns a new Vector instance comprised of the biggest respective components
255
     * out of this Vector and $that Vector.
256
     *
257
     * @param   Vector  $that       The Vector to compare to.
258
     * @return  Vector
259
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
260
     */
261
    public function componentMax(Vector $that) : Vector
262
    {
263
        if (!$this->isSameDimension($that)) {
264
            throw new \DomainException('The given Vector is not in the same dimension as this Vector.');
265
        }
266
267
        $result = [];
268
269
        foreach ($this->components as $i => $component) {
270
            $result[$i] = max($component, $that->components[$i]);
271
        }
272
273
        return new static($result);
274
    }
275
276
    /**
277
     * Returns a new Vector instance comprised of the smallest respective components
278
     * out of this Vector and $that Vector.
279
     *
280
     * @param   Vector  $that       The Vector to compare to.
281
     * @return  Vector
282
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
283
     */
284
    public function componentMin(Vector $that) : Vector
285
    {
286
        if (!$this->isSameDimension($that)) {
287
            throw new \DomainException('The given Vector is not in the same dimension as this Vector.');
288
        }
289
290
        $result = [];
291
292
        foreach ($this->components as $i => $component) {
293
            $result[$i] = min($component, $that->components[$i]);
294
        }
295
296
        return new static($result);
297
    }
298
299
    /**
300
     * Returns the dimension of the Vector.
301
     *
302
     * @return  int
303
     */
304
    public function dimension() : int
305
    {
306
        return count($this->components);
307
    }
308
309
    /**
310
     * Returns the distance of this Vector to the given Vector.
311
     *
312
     * @param   Vector      $that           The Vector to calculate the distance to.
313
     * @param   int|null    $type           The type of the distance (one of the DISTANCE_* class constants) or null
314
     *                                      to use the value of the public static $defaultDistanceType (Cartesian
315
     *                                      distance by default).
316
     * @return  float                       The distance of the specified type.
317
     * @throws  \InvalidArgumentException   When an unsupported distance type was given.
318
     */
319
    public function distance(Vector $that, int $type = null) : float
320
    {
321
        if (null === $type) {
322
            $type = static::$defaultDistanceType;
323
        }
324
325
        switch ($type) {
326
            case self::DISTANCE_CARTESIAN:
327
                return $this->cartesianDistanceTo($that);
328
329
            case self::DISTANCE_CHEBYSHEV:
330
            case self::DISTANCE_CHESSBOARD:
331
                return $this->chebyshevDistanceTo($that);
332
333
            case self::DISTANCE_TAXICAB:
334
            case self::DISTANCE_MANHATTAN:
335
                return $this->taxicabDistanceTo($that);
336
        }
337
338
        throw new \InvalidArgumentException('Unsupported distance type ['.$type.'] given.');
339
    }
340
341
    /**
342
     * Returns the cartesian distance of this Vector to the given Vector.
343
     *
344
     * @param   Vector  $that       The Vector to calculate the distance to.
345
     * @return  float               The cartesian distance.
346
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
347
     */
348 View Code Duplication
    public function cartesianDistanceTo(Vector $that) : float
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
349
    {
350
        if (!$this->isSameDimension($that)) {
351
            throw new \DomainException('The given input Vector is not in the same dimension as this Vector.');
352
        }
353
354
        $result = 0;
355
356
        foreach ($this->components as $i => $component) {
357
            $result += pow($component - $that->components[$i], 2);
358
        }
359
360
        return sqrt($result);
361
    }
362
363
    /**
364
     * Returns the Chebyshev (AKA chessboard) distance of this Vector to the given Vector.
365
     *
366
     * @param   Vector  $that       The Vector to calculate the distance to.
367
     * @return  float               The taxicab distance.
368
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
369
     */
370 View Code Duplication
    public function chebyshevDistanceTo(Vector $that) : float
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372
        if (!$this->isSameDimension($that)) {
373
            throw new \DomainException('The given input Vector is not in the same dimension as this Vector.');
374
        }
375
376
        $result = [];
377
378
        foreach ($this->components as $i => $component) {
379
            $result[$i] = abs($component - $that->components[$i]);
380
        }
381
382
        return max($result);
383
    }
384
385
    /**
386
     * Returns the taxicab (AKA Manhattan / city block / rectilinear) distance of this Vector to the given Vector.
387
     *
388
     * @param   Vector  $that       The Vector to calculate the distance to.
389
     * @return  float               The taxicab distance.
390
     * @throws  \DomainException    When the given Vector is not in the same space as this Vector.
391
     */
392
    public function taxicabDistanceTo(Vector $that) : float
393
    {
394
        if (!$this->isSameDimension($that)) {
395
            throw new \DomainException('The given input Vector is not in the same dimension as this Vector.');
396
        }
397
398
        $result = 0;
399
400
        foreach ($this->components as $i => $component) {
401
            $result += abs($component - $that->components[$i]);
402
        }
403
404
        return $result;
405
    }
406
407
    /**
408
     * Divides the Vector by the given scale and returns the result as a new Vector.
409
     *
410
     * @param   float   $scale              The scale to divide by.
411
     * @return  Vector                      The result of the division.
412
     * @throws  exceptions\DivisionByZero   When $scale is 0.f.
413
     */
414
    public function divide(float $scale) : Vector
415
    {
416
        if ($scale == 0) {
417
            throw new exceptions\DivisionByZero;
418
        }
419
420
        return $this->multiply(1.0 / $scale);
421
    }
422
423
    /**
424
     * Checks whether this Vector equals the given Vector, within the optional $tolerance.
425
     *
426
     * @param   Vector  $that               The Vector to compare to.
427
     * @param   float   $tolerance          The optional tolerance (to account for precision errors). Must be >= 0.
428
     * @return  bool
429
     * @throws  \InvalidArgumentException   When $tolerance is less than 0.
430
     * @throws  \DomainException            When the given Vector is not in the same space as this Vector.
431
     */
432
    public function equals(Vector $that, float $tolerance = 0.0) : bool
433
    {
434
        if (!$this->isSameDimension($that)) {
435
            throw new \DomainException('The given Vector is not in the same dimension as this Vector.');
436
        }
437
438
        if ($tolerance < 0) {
439
            throw new \InvalidArgumentException("Expected tolerance to be greater than or equal to 0, got [$tolerance] instead.");
440
        }
441
442
        foreach ($this->components as $i => $component) {
443
            if (abs($component - $that->components[$i]) > $tolerance) {
444
                return false;
445
            }
446
        }
447
448
        return true;
449
    }
450
451
    /**
452
     * Checks whether this Vector is of the same dimension as $that Vector.
453
     *
454
     * @param   Vector  $that   The Vector to check against.
455
     * @return  bool            True when the Vectors are of the same dimension, false otherwise.
456
     */
457
    public function isSameDimension(Vector $that) : bool
458
    {
459
        return count($this->components) === count($that->components);
460
    }
461
462
    /**
463
     * Returns the length of the Vector.
464
     *
465
     * @return  float
466
     */
467
    public function length() : float
468
    {
469
        static $result;
470
471
        return null !== $result ? $result : $result = sqrt($this->lengthSquared());
472
    }
473
474
    /**
475
     * Returns the square of the Vector's length.
476
     *
477
     * @return  float
478
     */
479
    public function lengthSquared() : float
480
    {
481
        static $result;
482
483
        // Return the cached result if it's available.
484
        if ($result !== null) {
485
            return $result;
486
        }
487
488
        // Compute the square sum.
489
        $sum = 0;
490
491
        foreach ($this->components as $component) {
492
            $sum += $component * $component;
493
        }
494
495
        return $result = $sum;
496
    }
497
498
    /**
499
     * Returns the smallest of the components.
500
     *
501
     * @return  float
502
     */
503
    public function min() : float
504
    {
505
        return min($this->components);
506
    }
507
508
    /**
509
     * Returns the biggest of the components.
510
     *
511
     * @return  float
512
     */
513
    public function max() : float
514
    {
515
        return max($this->components);
516
    }
517
518
    /**
519
     * Multiplies the Vector by the given scale and returns the result as a new Vector.
520
     *
521
     * @param   float   $scale  The scale to multiply by.
522
     * @return  Vector          The result of the multiplication.
523
     */
524 View Code Duplication
    public function multiply(float $scale) : Vector
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
525
    {
526
        $result = [];
527
528
        foreach ($this->components as $i => $component) {
529
            $result[$i] = $component * $scale;
530
        }
531
532
        return new static($result);
533
    }
534
535
    /**
536
     * Returns the normalized Vector, ie. a Vector with the same direction but a length of 1.
537
     *
538
     * @return  Vector                      The normalized vector.
539
     * @throws  exceptions\DivisionByZero   When the Vector's length is zero.
540
     */
541
    public function normalize() : Vector
542
    {
543
        return $this->divide($this->length());
544
    }
545
546
    /**
547
     * Projects this Vector onto another Vector.
548
     *
549
     * @param   Vector  $that   The vector to project this vector onto.
550
     * @return  Vector
551
     */
552
    public function projectOnto(Vector $that) : Vector
553
    {
554
        $that = $that->normalize();
555
556
        return $that->multiply($this->dotProduct($that));
557
    }
558
559
    /**
560
     * Reverses the direction of this Vector.
561
     *
562
     * @return  Vector
563
     */
564 View Code Duplication
    public function reverse()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
565
    {
566
        $result = [];
567
568
        foreach ($this->components as $i => $component) {
569
            $result[$i] = $component * -1;
570
        }
571
572
        return new static($result);
573
    }
574
575
    /**
576
     * Subtracts $that Vector/number from this Vector and returns the result as a new Vector.
577
     *
578
     * @param   Vector|number    $that      The Vector or (numeric) bias to subtract from this Vector.
579
     * @return  Vector                      The resulting difference as a new Vector instance.
580
     * @throws  \DomainException            When a Vector is given as input and it is not in the same space.
581
     * @throws  \InvalidArgumentException   When the value to add is neither a Vector nor numeric.
582
     */
583
    public function subtract($that) : Vector
584
    {
585
        $result = [];
586
587
        if ($that instanceof Vector) {
588
            if (!$this->isSameDimension($that)) {
589
                throw new \DomainException('The given input Vector is not in the same dimension as this Vector.');
590
            }
591
592
            foreach ($this->components as $i => $component) {
593
                $result[$i] = $component - $that->components[$i];
594
            }
595 View Code Duplication
        } elseif (is_numeric($that)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
596
            // We're accepting all numeric values but will be casting to a float, so be aware of potential
597
            // precision loss.
598
            $that = (float) $that;
599
600
            foreach ($this->components as $i => $component) {
601
                $result[$i] = $component - $that;
602
            }
603
        } else {
604
            throw new \InvalidArgumentException('Expected a Vector or a number to subtract, got ['.diagnostics\Debug::getTypeName($that).'] instead.');
605
        }
606
607
        return new static($result);
608
    }
609
610
    /**
611
     * @see self::get()
612
     *
613
     * @throws  \LogicException     When the given $key does not exist.
614
     */
615
    public function offsetGet($key)
616
    {
617
        if (!isset($this->components[$key])) {
618
            throw new \LogicException("The requested key [$key] does not exist.");
619
        }
620
621
        return $this->components[$key];
622
    }
623
624
    /**
625
     * {@inheritDoc}
626
     *
627
     * @throws  \LogicException     Always, since Vectors are immutable.
628
     */
629
    public function offsetSet($key, $item)
630
    {
631
        throw new \LogicException("Cannot set [$key] - Vectors are immutable.");
632
    }
633
634
    /**
635
     * @see self::has()
636
     */
637
    public function offsetExists($key)
638
    {
639
        return isset($this->components[$key]);
640
    }
641
642
    /**
643
     * {@inheritDoc}
644
     *
645
     * @throws  \LogicException     Always, since Vectors are immutable.
646
     */
647
    public function offsetUnset($key)
648
    {
649
        throw new \LogicException("Cannot unset [$key] - Vectors are immutable.");
650
    }
651
652
    /**
653
     * Magic getter. Allows access to some methods as properties and direct read access to the components.
654
     */
655
    public function __get($name)
656
    {
657
        if ('dimension' === $name || 'size' === $name) {
658
            return count($this->components);
659
        }
660
661
        if ('length' === $name) {
662
            return $this->length();
663
        }
664
665
        if ('min' === $name) {
666
            return $this->min();
667
        }
668
669
        if ('max' === $name) {
670
            return $this->max();
671
        }
672
673
        if (isset($this->components[$name])) {
674
            return $this->components[$name];
675
        }
676
677
        throw new \LogicException("Inaccessible method/property [$name].");
678
    }
679
}
680