Passed
Push — master ( 289f9d...bae7fb )
by Sebastian
04:42
created

OutputBuffering   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 13
eloc 46
c 1
b 0
f 0
dl 0
loc 172
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A flush() 0 13 2
A _stop() 0 12 2
A isActive() 0 3 1
A stop() 0 13 2
A setBaseBufferLevel() 0 3 1
A start() 0 12 2
A enableUnitTesting() 0 3 1
A get() 0 15 2
1
<?php
2
/**
3
 * File containing the class {@see \AppUtils\OutputBuffering}.
4
 *
5
 * @package Application Utils
6
 * @subpackage Output Buffering
7
 * @see \AppUtils\OutputBuffering
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
/**
15
 * Wrapper around the native PHP output buffering methods,
16
 * using exceptions to avoid having to check the return
17
 * values of the methods.
18
 *
19
 * It is limited to a typical output buffering usage:
20
 * starting a buffer, and retrieving or flushing its contents,
21
 * stopping the buffer in the process. Any more complex
22
 * buffer usage will have to use the PHP functions.
23
 *
24
 * @package Application Utils
25
 * @subpackage Output Buffering
26
 * @author Sebastian Mordziol <[email protected]>
27
 */
28
class OutputBuffering
29
{
30
    const ERROR_CANNOT_START = 91501;
31
    const ERROR_CANNOT_GET_BUFFER = 91502;
32
    const ERROR_BUFFER_NOT_STARTED = 91503;
33
    const ERROR_CANNOT_STOP_BUFFER = 91504;
34
    const ERROR_CANNOT_FLUSH_BUFFER = 91505;
35
36
    /**
37
     * @var int[]
38
     */
39
    private static $stack = array();
40
41
    /**
42
     * @var int
43
     */
44
    private static $baseLevel = 0;
45
46
    /**
47
     * Checks whether any level of output buffering is currently active.
48
     *
49
     * NOTE: Assumes by default that 0 is the inactive buffer level.
50
     * If this is not the case, see the {@see OutputBuffering::setBaseBufferLevel()}
51
     * method to adjust it.
52
     *
53
     * @return bool
54
     * @see OutputBuffering::setBaseBufferLevel()
55
     */
56
    public static function isActive() : bool
57
    {
58
        return ob_get_level() > self::$baseLevel;
59
    }
60
61
    /**
62
     * Starts a new output buffer.
63
     *
64
     * @throws OutputBuffering_Exception
65
     * @see OutputBuffering::ERROR_CANNOT_START
66
     */
67
    public static function start() : void
68
    {
69
        self::$stack[] = 1;
70
71
        if(ob_start() === true) {
72
            return;
73
        }
74
75
        throw new OutputBuffering_Exception(
76
            'Cannot start output buffering.',
77
            'ob_start returned false.',
78
            self::ERROR_CANNOT_START
79
        );
80
    }
81
82
    /**
83
     * Stops the output buffer, discarding the captured content.
84
     *
85
     * @throws OutputBuffering_Exception
86
     * @see OutputBuffering::ERROR_BUFFER_NOT_STARTED
87
     * @see OutputBuffering::ERROR_CANNOT_STOP_BUFFER
88
     */
89
    public static function stop() : void
90
    {
91
        self::_stop();
92
93
        if(ob_end_clean() !== false)
94
        {
95
            return;
96
        }
97
98
        throw new OutputBuffering_Exception(
99
            'Cannot stop the output buffer.',
100
            'The ob_end_clean call returned false.',
101
            self::ERROR_CANNOT_STOP_BUFFER
102
        );
103
    }
104
105
    /**
106
     * @throws OutputBuffering_Exception
107
     */
108
    private static function _stop() : void
109
    {
110
        if(empty(self::$stack))
111
        {
112
            throw new OutputBuffering_Exception(
113
                'Output buffering is not active',
114
                'Tried to get the output buffer, but none was active.',
115
                self::ERROR_BUFFER_NOT_STARTED
116
            );
117
        }
118
119
        array_pop(self::$stack);
120
    }
121
122
    /**
123
     * Flushes the captured output buffer to standard output.
124
     *
125
     * @throws OutputBuffering_Exception
126
     * @see OutputBuffering::ERROR_BUFFER_NOT_STARTED
127
     * @see OutputBuffering::ERROR_CANNOT_FLUSH_BUFFER
128
     */
129
    public static function flush() : void
130
    {
131
        self::_stop();
132
133
        if(ob_end_flush() !== false)
134
        {
135
            return;
136
        }
137
138
        throw new OutputBuffering_Exception(
139
            'Cannot flush the output buffer.',
140
            'ob_end_flush returned false.',
141
            self::ERROR_CANNOT_FLUSH_BUFFER
142
        );
143
    }
144
145
    /**
146
     * Retrieves the current output buffer's contents,
147
     * and stops the output buffer.
148
     *
149
     * @return string
150
     *
151
     * @throws OutputBuffering_Exception
152
     * @see OutputBuffering::ERROR_BUFFER_NOT_STARTED
153
     * @see OutputBuffering::ERROR_CANNOT_GET_BUFFER
154
     */
155
    public static function get() : string
156
    {
157
        self::_stop();
158
159
        $content = ob_get_clean();
160
161
        if($content !== false)
162
        {
163
            return $content;
164
        }
165
166
        throw new OutputBuffering_Exception(
167
            'Cannot stop the output buffer.',
168
            'ob_get_contents returned false.',
169
            self::ERROR_CANNOT_GET_BUFFER
170
        );
171
    }
172
173
    /**
174
     * Configure the output buffer to work in unit testing
175
     * mode, which assumes that the testing framework does
176
     * some output buffering of its own. This skews the
177
     * {@see OutputBuffering::isActive()} method, since it
178
     * assumes the buffer level must be 0 to be inactive.
179
     */
180
    public static function enableUnitTesting() : void
181
    {
182
        self::setBaseBufferLevel(1);
183
    }
184
185
    /**
186
     * Sets the base output buffering level. Any level
187
     * above this value is considered an active output
188
     * buffering level.
189
     *
190
     * Use this in case scripts outside your control
191
     * already have output buffering active. For example,
192
     * if your script always runs with 1 output buffering
193
     * level already being active, set the level to 1.
194
     *
195
     * @param int $level
196
     */
197
    public static function setBaseBufferLevel(int $level) : void
198
    {
199
        self::$baseLevel = $level;
200
    }
201
}
202