Text_Diff_Renderer::_context()   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
    /**
17
     * Number of leading context "lines" to preserve.
18
     *
19
     * This should be left at zero for this class, but subclasses may want to
20
     * set this to other values.
21
     */
22
    public $_leading_context_lines = 0;
23
24
    /**
25
     * Number of trailing context "lines" to preserve.
26
     *
27
     * This should be left at zero for this class, but subclasses may want to
28
     * set this to other values.
29
     */
30
    public $_trailing_context_lines = 0;
31
32
    /**
33
     * Constructor.
34
     * @param array $params
35
     */
36
    public function __construct($params = array())
37
    {
38
        foreach ($params as $param => $value) {
39
            $v = '_' . $param;
40
            if (isset($this->$v)) {
41
                $this->$v = $value;
42
            }
43
        }
44
    }
45
46
    /**
47
     * Get any renderer parameters.
48
     *
49
     * @return array All parameters of this renderer object.
50
     */
51
    public function getParams()
52
    {
53
        $params = array();
54
        foreach (get_object_vars($this) as $k => $v) {
55
            if ($k{0} == '_') {
56
                $params[substr($k, 1)] = $v;
57
            }
58
        }
59
60
        return $params;
61
    }
62
63
    /**
64
     * Renders a diff.
65
     *
66
     * @param Text_Diff $diff A Text_Diff object.
67
     *
68
     * @return string The formatted output.
69
     */
70
    public function render($diff)
71
    {
72
        $xi      = $yi = 1;
73
        $block   = false;
74
        $context = array();
75
76
        $nlead  = $this->_leading_context_lines;
77
        $ntrail = $this->_trailing_context_lines;
78
79
        $output = $this->_startDiff();
80
81
        foreach ($diff->getDiff() as $edit) {
82
            if (is_a($edit, 'Text_Diff_Op_copy')) {
83
                if (is_array($block)) {
84
                    if (count($edit->orig) <= $nlead + $ntrail) {
85
                        $block[] = $edit;
86
                    } else {
87
                        if ($ntrail) {
88
                            $context = array_slice($edit->orig, 0, $ntrail);
89
                            $block[] = new Text_Diff_Op_copy($context);
90
                        }
91
                        $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...
92
                        $block = false;
93
                    }
94
                }
95
                $context = $edit->orig;
96
            } else {
97
                if (!is_array($block)) {
98
                    $context = array_slice($context, count($context) - $nlead);
99
                    $x0      = $xi - count($context);
100
                    $y0      = $yi - count($context);
101
                    $block   = array();
102
                    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...
103
                        $block[] = new Text_Diff_Op_copy($context);
104
                    }
105
                }
106
                $block[] = $edit;
107
            }
108
109
            if ($edit->orig) {
110
                $xi += count($edit->orig);
111
            }
112
            if ($edit->final) {
113
                $yi += count($edit->final);
114
            }
115
        }
116
117
        if (is_array($block)) {
118
            $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
119
        }
120
121
        return $output . $this->_endDiff();
122
    }
123
124
    /**
125
     * @param $xbeg
126
     * @param $xlen
127
     * @param $ybeg
128
     * @param $ylen
129
     * @param $edits
130
     * @return string
131
     */
132
    public function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
133
    {
134
        $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
135
136
        foreach ($edits as $edit) {
137
            switch (strtolower(get_class($edit))) {
138
                case 'text_diff_op_copy':
139
                    $output .= $this->_context($edit->orig);
140
                    break;
141
142
                case 'text_diff_op_add':
143
                    $output .= $this->_added($edit->final);
144
                    break;
145
146
                case 'text_diff_op_delete':
147
                    $output .= $this->_deleted($edit->orig);
148
                    break;
149
150
                case 'text_diff_op_change':
151
                    $output .= $this->_changed($edit->orig, $edit->final);
152
                    break;
153
            }
154
        }
155
156
        return $output . $this->_endBlock();
157
    }
158
159
    /**
160
     * @return string
161
     */
162
    public function _startDiff()
163
    {
164
        return '';
165
    }
166
167
    /**
168
     * @return string
169
     */
170
    public function _endDiff()
171
    {
172
        return '';
173
    }
174
175
    /**
176
     * @param $xbeg
177
     * @param $xlen
178
     * @param $ybeg
179
     * @param $ylen
180
     * @return string
181
     */
182
    public function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
183
    {
184
        if ($xlen > 1) {
185
            $xbeg .= ',' . ($xbeg + $xlen - 1);
186
        }
187
        if ($ylen > 1) {
188
            $ybeg .= ',' . ($ybeg + $ylen - 1);
189
        }
190
191
        return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
192
    }
193
194
    /**
195
     * @param $header
196
     * @return string
197
     */
198
    public function _startBlock($header)
199
    {
200
        return $header . "\n";
201
    }
202
203
    /**
204
     * @return string
205
     */
206
    public function _endBlock()
207
    {
208
        return '';
209
    }
210
211
    /**
212
     * @param        $lines
213
     * @param string $prefix
214
     * @return string
215
     */
216
    public function _lines($lines, $prefix = ' ')
217
    {
218
        return $prefix . implode("\n$prefix", $lines) . "\n";
219
    }
220
221
    /**
222
     * @param $lines
223
     * @return string
224
     */
225
    public function _context($lines)
226
    {
227
        return $this->_lines($lines);
228
    }
229
230
    /**
231
     * @param $lines
232
     * @return string
233
     */
234
    public function _added($lines)
235
    {
236
        return $this->_lines($lines, '>');
237
    }
238
239
    /**
240
     * @param $lines
241
     * @return string
242
     */
243
    public function _deleted($lines)
244
    {
245
        return $this->_lines($lines, '<');
246
    }
247
248
    /**
249
     * @param $orig
250
     * @param $final
251
     * @return string
252
     */
253
    public function _changed($orig, $final)
254
    {
255
        return $this->_deleted($orig) . "---\n" . $this->_added($final);
256
    }
257
}
258