Completed
Push — dev ( 8ba0d3...e8a285 )
by Jordan
02:15
created

Numbers::makePi()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 18
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 9.2876

Importance

Changes 0
Metric Value
dl 18
loc 18
ccs 4
cts 9
cp 0.4444
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 3
nop 1
crap 9.2876
1
<?php
2
3
namespace Samsara\Fermat;
4
5
use Samsara\Exceptions\UsageError\IntegrityConstraint;
6
use Samsara\Fermat\Types\Base\CoordinateInterface;
7
use Samsara\Fermat\Types\Base\DecimalInterface;
8
use Samsara\Fermat\Types\Base\FractionInterface;
9
use Samsara\Fermat\Types\Fraction;
10
use Samsara\Fermat\Values\CartesianCoordinate;
11
use Samsara\Fermat\Values\Currency;
12
use Samsara\Fermat\Values\ImmutableFraction;
13
use Samsara\Fermat\Values\ImmutableNumber;
14
use Samsara\Fermat\Values\MutableFraction;
15
use Samsara\Fermat\Values\MutableNumber;
16
use Samsara\Fermat\Types\Base\NumberInterface;
17
18
class Numbers
19
{
20
21
    const MUTABLE = MutableNumber::class;
22
    const IMMUTABLE = ImmutableNumber::class;
23
    const MUTABLE_FRACTION = MutableFraction::class;
24
    const IMMUTABLE_FRACTION = ImmutableFraction::class;
25
    const CARTESIAN_COORDINATE = CartesianCoordinate::class;
26
    const CURRENCY = Currency::class;
27
    /* 105 digits after decimal, which is going to be overkill in almost all places */
28
    const PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679';
29
    /* Tau (2pi) to 100 digits */
30
    const TAU = '6.283185307179586476925286766559005768394338798750211641949889184615632812572417997256069650684234136';
31
    /* Euler's Number to 100 digits */
32
    const E = '2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427';
33
    /* Golden Ratio to 100 digits */
34
    const GOLDEN_RATIO = '1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137';
35
    /* Natural log of 10 to 100 digits */
36
    const LN_10 = '2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298';
37
38
    /**
39
     * @param $type
40
     * @param $value
41
     * @param int|null $precision
42
     * @param int $base
43
     *
44
     * @throws IntegrityConstraint
45
     * @return ImmutableNumber|MutableNumber|ImmutableFraction|MutableFraction|Currency|CartesianCoordinate|NumberInterface|FractionInterface|CoordinateInterface
46
     */
47 23
    public static function make($type, $value, $precision = null, $base = 10)
48
    {
49
50 23
        if (is_object($type)) {
51 18
            $type = get_class($type);
52
        }
53
54 23
        if ($type == static::IMMUTABLE) {
55 23
            return new ImmutableNumber(trim($value), $precision, $base);
56 1
        } elseif ($type == static::MUTABLE) {
57 1
            return new MutableNumber(trim($value), $precision, $base);
58
        } elseif ($type == static::IMMUTABLE_FRACTION) {
59
            return self::makeFractionFromString($value, $type)->convertToBase($base);
60
        } elseif ($type == static::MUTABLE_FRACTION) {
61
            return self::makeFractionFromString($value, $type)->convertToBase($base);
62
        } elseif ($type == static::CURRENCY) {
63
            return new Currency(trim($value), Currency::DOLLAR, $precision, $base);
64
        } elseif ($type == static::CARTESIAN_COORDINATE && is_array($value)) {
65
            return new CartesianCoordinate($value);
66
        } else {
67
            $reflector = new \ReflectionClass($type);
68
69
            if ($reflector->implementsInterface(FractionInterface::class) && $reflector->isSubclassOf(Fraction::class)) {
70
                return Numbers::makeFractionFromString($value, $reflector->getName(), $base);
0 ignored issues
show
Bug introduced by
Consider using $reflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
71
            }
72
73
            if ($reflector->implementsInterface(CoordinateInterface::class) && is_array($value)) {
74
                /** @var CoordinateInterface $customCoordinate */
75
                $customCoordinate = $reflector->newInstance([
76
                    $value
77
                ]);
78
                return $customCoordinate;
79
            }
80
81
            if ($reflector->implementsInterface(CoordinateInterface::class) && !is_array($value)) {
82
                throw new IntegrityConstraint(
83
                    'The $value for a CoordinateInterface must be an array',
84
                    'Provide an array for the $value',
85
                    'A CoordinateInterface expects the value to be an array of axes and values'
86
                );
87
            }
88
89
            if ($reflector->implementsInterface(NumberInterface::class)) {
90
                /** @var NumberInterface $customNumber */
91
                $customNumber = $reflector->newInstance([
92
                    trim($value),
93
                    $precision,
94
                    $base
95
                ]);
96
                return $customNumber;
97
            }
98
        }
99
100
        throw new IntegrityConstraint(
101
            '$type must be an implementation of NumberInterface',
102
            'Provide a type that implements NumberInterface (the Numbers class contains constants for the built in ones)',
103
            'The $type argument was not an implementation of NumberInterface'
104
        );
105
    }
106
107
    /**
108
     * @param $type
109
     * @param $value
110
     * @param int|null $precision
111
     * @param int $base
112
     * @return NumberInterface
113
     */
114
    public static function makeFromBase10($type, $value, $precision = null, $base = 10)
115
    {
116
        /**
117
         * @var ImmutableNumber|MutableNumber
118
         */
119
        $number = self::make($type, $value, $precision, 10);
120
121
        return $number->convertToBase($base);
0 ignored issues
show
Bug introduced by
The method convertToBase does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
122
    }
123
124
    /**
125
     * @param $type
126
     * @param int|float|string|NumberInterface|DecimalInterface|FractionInterface $value
127
     * @param int|null $precision
128
     * @param int $base
129
     *
130
     * @throws IntegrityConstraint
131
     * @return ImmutableNumber|MutableNumber|NumberInterface|ImmutableNumber[]|MutableNumber[]|NumberInterface[]
132
     */
133 25
    public static function makeOrDont($type, $value, $precision = null, $base = 10)
134
    {
135
136 25
        if (is_object($value)) {
137 23
            $reflector = new \ReflectionClass($value);
138
139 23
            if ($value instanceof $type) {
140 23
                return $value;
141
            }
142
143 1
            if ($reflector->implementsInterface(NumberInterface::class)) {
144 1
                return static::make($type, $value->getValue(), $precision, $base);
0 ignored issues
show
Bug introduced by
The method getValue does only exist in Samsara\Fermat\Types\Base\NumberInterface, but not in Samsara\Fermat\Types\Bas...\Base\FractionInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
145
            }
146 23
        } elseif (is_numeric($value)) {
147 23
            return static::make($type, $value, $precision, $base);
148
        } elseif (is_array($value)) {
149
            $newInput = [];
150
            
151
            foreach ($value as $key => $item) {
152
                $newInput[$key] = static::makeOrDont($type, $item, $precision, $base);
153
            }
154
155
            return $newInput;
156
        }
157
158
        throw new IntegrityConstraint(
159
            '$input must be an int, float, numeric string, or an implementation of NumberInterface',
160
            'Provide any of the MANY valid inputs',
161
            'The $input argument was not numeric or an implementation of NumberInterface.'
162
        );
163
164
    }
165
166
    /**
167
     * @param $value
168
     * @param $type
169
     *
170
     * @return ImmutableFraction|MutableFraction|FractionInterface
171
     * @throws IntegrityConstraint
172
     */
173
    public static function makeFractionFromString($value, $type = self::IMMUTABLE_FRACTION, $base = 10)
174
    {
175
        $parts = explode('/', $value);
176
177
        if (count($parts) > 2) {
178
            throw new IntegrityConstraint(
179
                'Only one division symbol (/) can be used',
180
                'Change the calling code to not provide more than one division symbol',
181
                'makeFractionFromString needs either one or zero division symbols in the $value argument; '.$value.' given'
182
            );
183
        }
184
185
        /** @var ImmutableNumber $numerator */
186
        $numerator = Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[0])))->round();
187
        /** @var ImmutableNumber $denominator */
188
        $denominator = isset($parts[1]) ? Numbers::make(Numbers::IMMUTABLE, trim(ltrim($parts[1])))->round() : Numbers::makeOne();
189
190
        if ($type == self::IMMUTABLE_FRACTION) {
191
            return new ImmutableFraction($numerator, $denominator, $base);
192
        } elseif ($type == self::MUTABLE_FRACTION) {
193
            return new MutableFraction($numerator, $denominator, $base);
194
        } else {
195
            $reflector = new \ReflectionClass($type);
196
197
            if ($reflector->implementsInterface(FractionInterface::class) && $reflector->isSubclassOf(Fraction::class)) {
198
                /** @var FractionInterface|Fraction $customFraction */
199
                $customFraction = $reflector->newInstance([
0 ignored issues
show
Bug Compatibility introduced by
The expression $reflector->newInstance(... $denominator, $base)); of type object adds the type Samsara\Fermat\Types\Fraction to the return on line 204 which is incompatible with the return type documented by Samsara\Fermat\Numbers::makeFractionFromString of type Samsara\Fermat\Types\Base\FractionInterface.
Loading history...
200
                    $numerator,
201
                    $denominator,
202
                    $base
203
                ]);
204
                return $customFraction;
205
            }
206
207
            throw new IntegrityConstraint(
208
                'Type must be ImmutableFraction or MutableFraction',
209
                'Alter to calling code to use the correct type',
210
                'makeFractionFromString can only make objects of type ImmutableFraction or MutableFraction; '.$type.' given'
211
            );
212
        }
213
    }
214
215
    /**
216
     * @param int|null $precision
217
     *
218
     * @throws IntegrityConstraint
219
     * @return NumberInterface
220
     */
221 5 View Code Duplication
    public static function makePi($precision = null)
0 ignored issues
show
Duplication introduced by
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...
222
    {
223
        
224 5
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
225
            throw new IntegrityConstraint(
226
                '$precision must be between 1 and 100 inclusive',
227
                'Provide a precision within range',
228
                'The PI constant cannot have a precision higher than the constant stored (100)'
229
            );
230
        }
231
        
232 5
        if (!is_null($precision)) {
233
            return self::make(self::IMMUTABLE, self::PI, $precision)->roundToPrecision($precision);
234
        } else {
235 5
            return self::make(self::IMMUTABLE, self::PI, 100);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::IMMUTABLE, self::PI, 100); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makePi of type Samsara\Fermat\Types\Base\NumberInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
236
        }
237
        
238
    }
239
240
    /**
241
     * @param int|null $precision
242
     *
243
     * @throws IntegrityConstraint
244
     * @return NumberInterface
245
     */
246 6 View Code Duplication
    public static function makeTau($precision = null)
0 ignored issues
show
Duplication introduced by
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...
247
    {
248 6
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
249
            throw new IntegrityConstraint(
250
                '$precision must be between 1 and 100 inclusive',
251
                'Provide a precision within range',
252
                'The TAU constant cannot have a precision higher than the constant stored (100)'
253
            );
254
        }
255
256 6
        if (!is_null($precision)) {
257
            return self::make(self::IMMUTABLE, self::TAU, $precision)->roundToPrecision($precision);
258
        } else {
259 6
            return self::make(self::IMMUTABLE, self::TAU, 100);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::...TABLE, self::TAU, 100); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeTau of type Samsara\Fermat\Types\Base\NumberInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
260
        }
261
    }
262
263
    /**
264
     * @param int|null $precision
265
     *
266
     * @return NumberInterface
267
     */
268 6
    public static function make2Pi($precision = null)
269
    {
270 6
        return self::makeTau($precision);
271
    }
272
273
    /**
274
     * @param int|null $precision
275
     *
276
     * @throws IntegrityConstraint
277
     * @return NumberInterface
278
     */
279 4 View Code Duplication
    public static function makeE($precision = null)
0 ignored issues
show
Duplication introduced by
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...
280
    {
281
282 4
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
283
            throw new IntegrityConstraint(
284
                '$precision must be between 1 and 100 inclusive',
285
                'Provide a precision within range',
286
                'The E constant cannot have a precision higher than the constant stored (100)'
287
            );
288
        }
289
290 4
        if (!is_null($precision)) {
291
            return self::make(self::IMMUTABLE, self::E, $precision)->roundToPrecision($precision);
292
        } else {
293 4
            return self::make(self::IMMUTABLE, self::E, 100);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::IMMUTABLE, self::E, 100); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeE of type Samsara\Fermat\Types\Base\NumberInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
294
        }
295
296
    }
297
298
    /**
299
     * @param int|null $precision
300
     *
301
     * @throws IntegrityConstraint
302
     * @return NumberInterface
303
     */
304 View Code Duplication
    public static function makeGoldenRatio($precision = null)
0 ignored issues
show
Duplication introduced by
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...
305
    {
306
307
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
308
            throw new IntegrityConstraint(
309
                '$precision must be between 1 and 100 inclusive',
310
                'Provide a precision within range',
311
                'The Golden Ratio constant cannot have a precision higher than the constant stored (100)'
312
            );
313
        }
314
315
        if (!is_null($precision)) {
316
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, $precision)->roundToPrecision($precision);
317
        } else {
318
            return self::make(self::IMMUTABLE, self::GOLDEN_RATIO, 100);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::...lf::GOLDEN_RATIO, 100); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeGoldenRatio of type Samsara\Fermat\Types\Base\NumberInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
319
        }
320
321
    }
322
323
    /**
324
     * @param int|null $precision
325
     *
326
     * @throws IntegrityConstraint
327
     * @return NumberInterface
328
     */
329 1 View Code Duplication
    public static function makeNaturalLog10($precision = null)
0 ignored issues
show
Duplication introduced by
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...
330
    {
331
332 1
        if (!is_null($precision) && ($precision > 100 || $precision < 1)) {
333
            throw new IntegrityConstraint(
334
                '$precision must be between 1 and 100 inclusive',
335
                'Provide a precision within range',
336
                'The natural log of 10 constant cannot have a precision higher than the constant stored (100)'
337
            );
338
        }
339
340 1
        if (!is_null($precision)) {
341
            return self::make(self::IMMUTABLE, self::LN_10, $precision)->roundToPrecision($precision);
342
        } else {
343 1
            return self::make(self::IMMUTABLE, self::LN_10, 100);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::...BLE, self::LN_10, 100); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeNaturalLog10 of type Samsara\Fermat\Types\Base\NumberInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
344
        }
345
346
    }
347
348
    /**
349
     * @return ImmutableNumber
350
     */
351 12
    public static function makeOne($precision = null)
352
    {
353 12
        return self::make(self::IMMUTABLE, 1, $precision);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::IMMUTABLE, 1, $precision); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeOne of type Samsara\Fermat\Values\ImmutableNumber.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
354
    }
355
356
    /**
357
     * @return ImmutableNumber
358
     */
359 12
    public static function makeZero($precision = null)
360
    {
361 12
        return self::make(self::IMMUTABLE, 0, $precision);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return self::make(self::IMMUTABLE, 0, $precision); (Samsara\Fermat\Types\Bas...ase\CoordinateInterface) is incompatible with the return type documented by Samsara\Fermat\Numbers::makeZero of type Samsara\Fermat\Values\ImmutableNumber.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
362
    }
363
364
}