Text_Diff_Renderer::_added()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * A class to render Diffs in different formats.
5
 *
6
 * This class renders the diff in classic diff format. It is intended that
7
 * this class be customized via inheritance, to obtain fancier outputs.
8
 *
9
 * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.9 2005/05/04 20:21:52 chuck Exp $
10
 *
11
 * @package Text_Diff
12
 */
13
class Text_Diff_Renderer
14
{
15
    /**
16
     * Number of leading context "lines" to preserve.
17
     *
18
     * This should be left at zero for this class, but subclasses may want to
19
     * set this to other values.
20
     */
21
    public $_leading_context_lines = 0;
22
23
    /**
24
     * Number of trailing context "lines" to preserve.
25
     *
26
     * This should be left at zero for this class, but subclasses may want to
27
     * set this to other values.
28
     */
29
    public $_trailing_context_lines = 0;
30
31
    /**
32
     * Constructor.
33
     * @param array $params
34
     */
35
    public function __construct($params = array())
36
    {
37
        foreach ($params as $param => $value) {
38
            $v = '_' . $param;
39
            if (isset($this->$v)) {
40
                $this->$v = $value;
41
            }
42
        }
43
    }
44
45
    /**
46
     * Get any renderer parameters.
47
     *
48
     * @return array All parameters of this renderer object.
49
     */
50
    public function getParams()
51
    {
52
        $params = array();
53
        foreach (get_object_vars($this) as $k => $v) {
54
            if ($k{0} === '_') {
55
                $params[substr($k, 1)] = $v;
56
            }
57
        }
58
59
        return $params;
60
    }
61
62
    /**
63
     * Renders a diff.
64
     *
65
     * @param Text_Diff $diff A Text_Diff object.
66
     *
67
     * @return string The formatted output.
68
     */
69
    public function render($diff)
70
    {
71
        $xi      = $yi = 1;
72
        $block   = false;
73
        $context = array();
74
75
        $nlead  = $this->_leading_context_lines;
76
        $ntrail = $this->_trailing_context_lines;
77
78
        $output = $this->_startDiff();
79
80
        foreach ($diff->getDiff() as $edit) {
81
            if (is_a($edit, 'Text_Diff_Op_copy')) {
82
                if (is_array($block)) {
83
                    if (count($edit->orig) <= $nlead + $ntrail) {
84
                        $block[] = $edit;
85
                    } else {
86
                        if ($ntrail) {
87
                            $context = array_slice($edit->orig, 0, $ntrail);
88
                            $block[] = new Text_Diff_Op_copy($context);
89
                        }
90
                        $output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
0 ignored issues
show
Bug introduced by
The variable $x0 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $y0 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
91
                        $block  = false;
92
                    }
93
                }
94
                $context = $edit->orig;
95
            } else {
96
                if (!is_array($block)) {
97
                    $context = array_slice($context, count($context) - $nlead);
98
                    $x0      = $xi - count($context);
99
                    $y0      = $yi - count($context);
100
                    $block   = array();
101
                    if ($context) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $context of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
102
                        $block[] = new Text_Diff_Op_copy($context);
103
                    }
104
                }
105
                $block[] = $edit;
106
            }
107
108
            if ($edit->orig) {
109
                $xi += count($edit->orig);
110
            }
111
            if ($edit->final) {
112
                $yi += count($edit->final);
113
            }
114
        }
115
116
        if (is_array($block)) {
117
            $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
118
        }
119
120
        return $output . $this->_endDiff();
121
    }
122
123
    /**
124
     * @param $xbeg
125
     * @param $xlen
126
     * @param $ybeg
127
     * @param $ylen
128
     * @param $edits
129
     * @return string
130
     */
131
    public function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
132
    {
133
        $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
134
135
        foreach ($edits as $edit) {
136
            switch (strtolower(get_class($edit))) {
137
                case 'text_diff_op_copy':
138
                    $output .= $this->_context($edit->orig);
139
                    break;
140
141
                case 'text_diff_op_add':
142
                    $output .= $this->_added($edit->final);
143
                    break;
144
145
                case 'text_diff_op_delete':
146
                    $output .= $this->_deleted($edit->orig);
147
                    break;
148
149
                case 'text_diff_op_change':
150
                    $output .= $this->_changed($edit->orig, $edit->final);
151
                    break;
152
            }
153
        }
154
155
        return $output . $this->_endBlock();
156
    }
157
158
    /**
159
     * @return string
160
     */
161
    public function _startDiff()
162
    {
163
        return '';
164
    }
165
166
    /**
167
     * @return string
168
     */
169
    public function _endDiff()
170
    {
171
        return '';
172
    }
173
174
    /**
175
     * @param $xbeg
176
     * @param $xlen
177
     * @param $ybeg
178
     * @param $ylen
179
     * @return string
180
     */
181
    public function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
182
    {
183
        if ($xlen > 1) {
184
            $xbeg .= ',' . ($xbeg + $xlen - 1);
185
        }
186
        if ($ylen > 1) {
187
            $ybeg .= ',' . ($ybeg + $ylen - 1);
188
        }
189
190
        return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
191
    }
192
193
    /**
194
     * @param $header
195
     * @return string
196
     */
197
    public function _startBlock($header)
198
    {
199
        return $header . "\n";
200
    }
201
202
    /**
203
     * @return string
204
     */
205
    public function _endBlock()
206
    {
207
        return '';
208
    }
209
210
    /**
211
     * @param         $lines
212
     * @param  string $prefix
213
     * @return string
214
     */
215
    public function _lines($lines, $prefix = ' ')
216
    {
217
        return $prefix . implode("\n$prefix", $lines) . "\n";
218
    }
219
220
    /**
221
     * @param $lines
222
     * @return string
223
     */
224
    public function _context($lines)
225
    {
226
        return $this->_lines($lines);
227
    }
228
229
    /**
230
     * @param $lines
231
     * @return string
232
     */
233
    public function _added($lines)
234
    {
235
        return $this->_lines($lines, '>');
236
    }
237
238
    /**
239
     * @param $lines
240
     * @return string
241
     */
242
    public function _deleted($lines)
243
    {
244
        return $this->_lines($lines, '<');
245
    }
246
247
    /**
248
     * @param $orig
249
     * @param $final
250
     * @return string
251
     */
252
    public function _changed($orig, $final)
253
    {
254
        return $this->_deleted($orig) . "---\n" . $this->_added($final);
255
    }
256
}
257