File: Warning.php

package info (click to toggle)
php-pear 1%3A1.10.16%2Bsubmodules%2Bnotgz-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,576 kB
  • sloc: php: 52,994; ansic: 39,986; xml: 33,278; yacc: 677; pascal: 452; makefile: 122; sh: 114
file content (376 lines) | stat: -rw-r--r-- 11,831 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
<?php
/**
 * PEAR, the PHP Extension and Application Repository
 *
 * PEAR Warning class
 *
 * PHP versions 4 and 5
 *
 * @category   pear
 * @package    PEAR
 * @author     Greg Beaver <cellog@php.net>
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 * @link       http://pear.php.net/package/PEAR
 */

require_once 'PEAR/Exception.php';

/**
 * Exception class for internal PEAR_Warning exceptions
 * @package PEAR
 */
class PEAR_WarningException extends PEAR_Exception {}

interface PEAR_WarningInterface
{
    /**
     * Get the severity of this warning ('warning', 'notice')
     * @return string
     */
    public function getLevel();
}

/**
 * Warning mechanism for PEAR PHP5-only packages.
 *
 * For users:
 *
 * Unlike PEAR_ErrorStack, PEAR_Warning is designed to be used on a transactional basis.
 *
 * <code>
 * <?php
 * require_once 'PEAR/Warning.php';
 * require_once 'PEAR/Exception.php';
 * class Mypackage_Exception extends PEAR_Exception {}
 * PEAR_Warning::begin();
 * $c = new Somepackage;
 * $c->doSomethingComplex();
 * if (PEAR_Warning::hasWarnings()) {
 *     $warnings = PEAR_Warning::end();
 *     throw new Mypackage_Exception('unclean doSomethingComplex', $warnings);
 * } else {
 *     $c->doSomethingElse();
 * }
 * ?>
 * </code>
 *
 * Only warnings that occur between ::begin() and ::end() will be processed.  Remember,
 * a warning is a non-fatal error, exceptions will be used for unrecoverable errors in
 * all PEAR packages, and you should follow this model to be safe!
 * 
 * For developers:
 *
 * This class can be used globally or locally.  For global use, a
 * series of static methods have been provided.  The class is designed
 * for lazy loading, and so the following code will work, and increase
 * efficiency on production servers:
 *
 * <code>
 * <?php
 * if (class_exists('PEAR_Warning')) {
 *     PEAR_Warning::add(1, 'mypackage', 'possible mis-spelling of something');
 * }
 * ?>
 * </code>
 *
 * This means that PEAR_Warning can literally be used without the need for
 * require_once 'PEAR/Warning.php';!
 *
 * You can also pass in an exception class as a warning
 *
 * <code>
 * <?php
 * class MyPackage_Warning extends PEAR_Exception {}
 * PEAR_Warning::add(new MyPackage_Warning('some info'));
 * ?>
 * </code>
 *
 * An interface is provided to allow for severity differentiation
 *
 * <code>
 * <?php
 * class MyPackage_Warning extends PEAR_Exception implements PEAR_WarningInterface
 * {
 *     private $_level = 'warning';
 *     function __construct($message, $level = 'warning', $p1 = null, $p2 = null)
 *     {
 *         $this->_level = $level;
 *         parent::__construct($message, $p1, $p2);
 *     }
 *
 *     public function getLevel()
 *     {
 *         return $this->_level;
 *     }
 * }
 * PEAR_Warning::add(new MyPackage_Warning('some info', 'notice'));
 * ?>
 * </code>
 *
 * This can be used with {@link setErrorHandling()} to ignore warnings of different severities
 * for complex error situations.
 *
 * For local situations like an internal warning system for a parser that may become the cause
 * of a single PEAR_Exception, PEAR_Warning can also be instantiated and used without any connection
 * to the global warning stack.
 * @package PEAR
 */
class PEAR_Warning
{
    /**
     * properties used for global warning stacks
     */
    protected static $_hasWarnings = false;

    protected static $warnings = array();
    protected static $go = false;
    protected static $levels = array('warning', 'notice');

    private static $_observers = array();
    private static $_uniqueid = 0;
    /**
     * properties used for instantiation of private warning stack
     */
    private $_warnings = array();
    private $_go = false;
    private $_context;

    /**
     * Begin tracking all global warnings
     */
    static public function begin()
    {
        if (class_exists('PEAR_ErrorStack')) {
            PEAR_ErrorStack::setPEARWarningCallback(array('PEAR_Warning', '_catch'));
        }
        self::$go = true;
        self::$_hasWarnings = false;
    }

    /**
     * @return bool
     */
    static public function hasWarnings()
    {
        return self::$_hasWarnings;
    }

    /**
     * Stop tracking global warnings
     * @return array an array of all warnings in array and PEAR_Exception format
     *               suitable for use as a PEAR_Exception cause
     */
    static public function end()
    {
        if (class_exists('PEAR_ErrorStack')) {
            PEAR_ErrorStack::setPEARWarningCallback(false);
        }
        self::$go = false;
        self::$_hasWarnings = false;
        $a = self::$warnings;
        self::$warnings = array();
        return $a;
    }

    /**
     * @param mixed A valid callback that accepts either a
     *              PEAR_Exception or PEAR_ErrorStack-style array
     * @param string The name of the observer. Use this if you want
     *               to remove it later with removeObserver().
     *               {@link getUniqueId()} can be used to generate a label
     */
    public static function addObserver($callback, $label = 'default')
    {
        self::$_observers[$label] = $callback;
    }

    /**
     * @param mixed observer ID
     */
    public static function removeObserver($label = 'default')
    {
        unset(self::$_observers[$label]);
    }

    /**
     * @return int unique identifier for an observer
     */
    public static function getUniqueId()
    {
        return self::$_uniqueid++;
    }

    /**
     * Set the warning levels that should be captured by the warning mechanism
     *
     * WARNING: no error checking or spell checking.
     * @param array
     */
    public static function setErrorHandling($levels)
    {
        self::$_levels = $levels;
    }

    /**
     * Add a warning to the global warning stack.
     *
     * Note: if you want file/line context, use an exception object
     * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an
     *                                  error code or some other error class differentiation technique
     * @param string Package is required if $codeOrException is not a PEAR_Exception object
     * @param string Error message, use %param% to do automatic parameter replacement from $params
     * @param array  Error parameters
     * @param string Error level, use the English name

     * @throws PEAR_WarningException if $codeOrException is not a PEAR_Exception and $package is not set
     */
    static public function add($codeOrException, $package = '', $msg = '', $params = array(),
                               $level = 'warning')
    {
        if ($codeOrException instanceof PEAR_Exception) {
            if ($codeOrException instanceof PEAR_WarningInterface) {
                if (in_array($codeOrException->getLevel(), self::$levels)) {
                    self::_signal($codeOrException);
                }
            } else {
                self::_signal($codeOrException);
            }
        } else {
            if (empty($package)) {
                throw new PEAR_WarningException('Package must be set for a non-exception warning');
            }
            if (in_array($level, self::$levels)) {
                $warning = self::_formatWarning($codeOrException, $package, $level, $msg, $params);
                self::_signal($warning);
            }
        }
        if (self::$go) {
            self::$_hasWarnings = true;
            self::$warnings[] = $warning;
        }
    }

    /**
     * @param string the package name, or other context information that can be used
     *               to differentiate this warning from warnings thrown by other packages
     * @throws PEAR_WarningException if $context is not a string
     */
    public function __construct($context)
    {
        if (!is_string($context)) {
            throw new PEAR_WarningException('$context constructor argument must be a string');
        }
        $this->_context = $context;
    }

    /**
     * Local stack function for adding a warning - note that package is not needed, as it is
     * defined in the constructor.
     *
     * Note: if you want file/line context, use an exception object
     * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an
     *                                  error code or some other error class differentiation technique
     * @param string Error message, use %param% to do automatic parameter replacement from $params
     * @param array  Error parameters
     * @param string Error level, use the English name
     */
    public function localAdd($code, $msg = '', $params = array(), $level = 'warning')
    {
        if ($codeOrException instanceof PEAR_Exception) {
            $this->_warnings[] = $codeOrException;
        } else {
            $warning = self::_formatWarning($codeOrException, $this->_context, $level, $msg);
            $this->_warnings[] = $warning;
        }
    }

    /**
     * Begin a local warning stack session
     */
    public function localBegin()
    {
        $this->_warnings = array();
        $this->_go = true;
    }

    /**
     * End a local warning stack session
     * @return array
     */
    public function localEnd()
    {
        $a = $this->_warnings;
        $this->_warnings = array();
        $this->_go = false;
        return $a;
    }

    /**
     * Do not use this function directly - it should only be used by PEAR_ErrorStack
     * @access private
     */
    static public function _catch($err)
    {
        self::_signal($err);
    }

    private static function _signal($warning)
    {
        foreach (self::$_observers as $func) {
            if (is_callable($func)) {
                call_user_func($func, $this);
                continue;
            }
            settype($func, 'array');
            switch ($func[0]) {
                case PEAR_EXCEPTION_PRINT :
                    $f = (isset($func[1])) ? $func[1] : '%s';
                    printf($f, $this->getMessage());
                    break;
                case PEAR_EXCEPTION_TRIGGER :
                    $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
                    trigger_error($this->getMessage(), $f);
                    break;
                case PEAR_EXCEPTION_DIE :
                    $f = (isset($func[1])) ? $func[1] : '%s';
                    die(printf($f, $this->getMessage()));
                    break;
                default:
                    trigger_error('invalid observer type', E_USER_WARNING);
            }
        }
    }

    static private function _formatWarning($code, $package, $level, $msg, $params, $backtrace)
    {
        return array('package' => $package,
                     'code' => $code, 
                     'level' => $level,
                     'message' => self::_formatMessage($msg, $params),
                     'params' => $params);
    }
    
    static private function _formatMessage($msg, $params)
    {
        if (count($params)) {
            foreach ($params as $name => $val) {
                if (strpos($msg, '%' . $name . '%') !== false) {
                    if (is_array($val)) {
                        // don't pass in an array that you expect to display unless it is 1-dimensional!
                        $val = implode(', ', $val);
                    }
                    if (is_object($val)) {
                        if (method_exists($val, '__toString')) {
                            $val = $val->__toString();
                        } else {
                            $val = 'Object';
                        }
                    }
                    $msg = str_replace('%' . $name . '%', $val, $msg);
                }
            }
        }
        return $msg;
    }
}
?>