Completed
Push — master ( 246dd7...ca0f65 )
by Kamil
03:43
created

ThrowableProxy::getContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Dazzle\Throwable;
4
5
/**
6
 * Throwables were designed to handle exceptional states that can occur in application during execution. They were not
7
 * meant to be used in business logic, however in practice, many design patterns emerged that used Throwables as a type
8
 * representation of failure, for which application needed to react. In other programming languages Throwables are
9
 * populated with data not on creation but while throwing. In PHP it works differently, and Throwables are populated
10
 * on creation. This can lead to major problems with memory and performance with usage of previously mentioned design
11
 * patterns. In those cases the valuable pieces of information are Throwable class, message, code and previous element,
12
 * but not stack trace that requires most of memory allocation. For this exclusive need ThrowableProxy has been created.
13
 * Its main purpose is to create a placeholders for Throwable most needed data discarding all not needed traces.
14
 *
15
 * TLDR: This class should be used in design patterns which logic represents failures as throwables, and does not
16
 * necessarily need stack information.
17
 */
18
class ThrowableProxy
19
{
20
    /**
21
     * @var string
22
     */
23
    protected $class;
24
25
    /**
26
     * @var string
27
     */
28
    protected $message;
29
30
    /**
31
     * @var \Error|\Exception|ThrowableProxy|null
32
     */
33
    protected $prev;
34
35
    /**
36
     * @var mixed[]
37
     */
38
    protected $context;
39
40
    /**
41
     * @param \Error|\Exception|string[]|string $throwableOrMessage
42
     */
43 14
    public function __construct($throwableOrMessage)
44
    {
45 14
        if ($throwableOrMessage instanceof \Error || $throwableOrMessage instanceof \Exception)
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
46
        {
47 10
            $prev = $throwableOrMessage->getPrevious();
48
49 10
            $this->class = get_class($throwableOrMessage);
50 10
            $this->message = $throwableOrMessage->getMessage();
51 10
            $this->prev = $prev === null ? null : new ThrowableProxy($prev);
52
        }
53 4
        else if (is_array($throwableOrMessage))
54
        {
55 1
            $this->class = $throwableOrMessage[0];
56 1
            $this->message = $throwableOrMessage[1];
57 1
            $this->prev = null;
58
        }
59
        else
60
        {
61 3
            $this->class = 'Exception';
62 3
            $this->message = $throwableOrMessage;
63 3
            $this->prev = null;
64
        }
65 14
    }
66
67
    /**
68
     *
69
     */
70 19
    public function __destruct()
71
    {
72 19
        unset($this->class);
73 19
        unset($this->message);
74 19
        unset($this->prev);
75 19
    }
76
77
    /**
78
     * @param mixed[] $context
79
     */
80
    public function setContext(array $context = [])
81
    {
82
        $this->context = $context;
83
    }
84
85
    /**
86
     * @return mixed[]
87
     */
88
    public function getContext()
89
    {
90
        return $this->context;
91
    }
92
93
    /**
94
     * Format proxied Throwable as string.
95
     *
96
     * @return string
97
     */
98 1
    public function __toString()
99
    {
100 1
        return Exception::toString($this->toThrowable());
101
    }
102
103
    /**
104
     * Return proxied Throwable.
105
     *
106
     * @return \Error|\Exception
107
     */
108 10
    public function toThrowable()
109
    {
110 10
        $class = $this->class;
111 10
        $prev  = $this->prev !== null ? $this->prev->toThrowable() : $this->prev;
0 ignored issues
show
Bug introduced by
The method toThrowable does only exist in Dazzle\Throwable\ThrowableProxy, but not in Exception.

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...
112
113 10
        return new $class($this->message, 0, $prev);
114
    }
115
116
    /**
117
     * Return proxied Throwable message.
118
     *
119
     * @return string
120
     */
121 1
    final public function getMessage()
122
    {
123 1
        return $this->message;
124
    }
125
126
    /**
127
     * Return proxied Throwable code.
128
     *
129
     * @return int
130
     */
131 1
    final public function getCode()
132
    {
133 1
        return $this->toThrowable()->getCode();
134
    }
135
136
    /**
137
     * Return proxied Throwable file.
138
     *
139
     * @return string
140
     */
141 1
    final public function getFile()
142
    {
143 1
        return $this->toThrowable()->getFile();
144
    }
145
146
    /**
147
     * Return proxied Throwable code.
148
     *
149
     * @return int
150
     */
151 1
    final public function getLine()
152
    {
153 1
        return $this->toThrowable()->getLine();
154
    }
155
156
    /**
157
     * Return proxied Throwable trace.
158
     *
159
     * @return array
160
     */
161 1
    final public function getTrace()
162
    {
163 1
        return $this->toThrowable()->getTrace();
164
    }
165
166
    /**
167
     * Return proxied Throwable previous element.
168
     *
169
     * @return \Error|\Exception|null
170
     */
171 2
    final public function getPrevious()
172
    {
173 2
        return $this->prev !== null ? $this->prev->toThrowable() : $this->prev;
0 ignored issues
show
Bug introduced by
The method toThrowable does only exist in Dazzle\Throwable\ThrowableProxy, but not in Exception.

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...
174
    }
175
176
    /**
177
     * Return proxied Throwable trace in string format.
178
     *
179
     * @return string
180
     */
181 1
    final public function getTraceAsString()
182
    {
183 1
        return $this->toThrowable()->getTraceAsString();
184
    }
185
}
186