1<?php
2
3/**
4 * Hoa
5 *
6 *
7 * @license
8 *
9 * New BSD License
10 *
11 * Copyright © 2007-2017, Hoa community. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *     * Redistributions of source code must retain the above copyright
16 *       notice, this list of conditions and the following disclaimer.
17 *     * Redistributions in binary form must reproduce the above copyright
18 *       notice, this list of conditions and the following disclaimer in the
19 *       documentation and/or other materials provided with the distribution.
20 *     * Neither the name of the Hoa nor the names of its contributors may be
21 *       used to endorse or promote products derived from this software without
22 *       specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37namespace Hoa\Consistency
38{
39
40/**
41 * Class Hoa\Consistency\Consistency.
42 *
43 * This class is a collection of tools to ensure foreward and backward
44 * compatibility.
45 *
46 * @copyright  Copyright © 2007-2017 Hoa community
47 * @license    New BSD License
48 */
49class Consistency
50{
51    /**
52     * Check if an entity exists (class, interface, trait…).
53     *
54     * @param   string  $entityName    Entity name.
55     * @param   bool    $autoloader    Run autoloader if necessary.
56     * @return  bool
57     */
58    public static function entityExists($entityName, $autoloader = false)
59    {
60        return
61            class_exists($entityName, $autoloader) ||
62            interface_exists($entityName, false)   ||
63            trait_exists($entityName, false);
64    }
65
66    /**
67     * Get the shortest name for an entity.
68     *
69     * @param   string  $entityName    Entity name.
70     * @return  string
71     */
72    public static function getEntityShortestName($entityName)
73    {
74        $parts = explode('\\', $entityName);
75        $count = count($parts);
76
77        if (1 >= $count) {
78            return $entityName;
79        }
80
81        if ($parts[$count - 2] === $parts[$count - 1]) {
82            return implode('\\', array_slice($parts, 0, -1));
83        }
84
85        return $entityName;
86    }
87
88    /**
89     * Declare a flex entity (for nested library).
90     *
91     * @param   string  $entityName    Entity name.
92     * @return  bool
93     */
94    public static function flexEntity($entityName)
95    {
96        return class_alias(
97            $entityName,
98            static::getEntityShortestName($entityName),
99            false
100        );
101    }
102
103    /**
104     * Whether a word is reserved or not.
105     *
106     * @param   string  $word    Word.
107     * @return  bool
108     */
109    public static function isKeyword($word)
110    {
111        static $_list = [
112            // PHP keywords.
113            '__halt_compiler',
114            'abstract',
115            'and',
116            'array',
117            'as',
118            'bool',
119            'break',
120            'callable',
121            'case',
122            'catch',
123            'class',
124            'clone',
125            'const',
126            'continue',
127            'declare',
128            'default',
129            'die',
130            'do',
131            'echo',
132            'else',
133            'elseif',
134            'empty',
135            'enddeclare',
136            'endfor',
137            'endforeach',
138            'endif',
139            'endswitch',
140            'endwhile',
141            'eval',
142            'exit',
143            'extends',
144            'false',
145            'final',
146            'float',
147            'for',
148            'foreach',
149            'function',
150            'global',
151            'goto',
152            'if',
153            'implements',
154            'include',
155            'include_once',
156            'instanceof',
157            'insteadof',
158            'int',
159            'interface',
160            'isset',
161            'list',
162            'mixed',
163            'namespace',
164            'new',
165            'null',
166            'numeric',
167            'object',
168            'or',
169            'print',
170            'private',
171            'protected',
172            'public',
173            'require',
174            'require_once',
175            'resource',
176            'return',
177            'static',
178            'string',
179            'switch',
180            'throw',
181            'trait',
182            'true',
183            'try',
184            'unset',
185            'use',
186            'var',
187            'void',
188            'while',
189            'xor',
190            'yield',
191
192            // Compile-time constants.
193            '__class__',
194            '__dir__',
195            '__file__',
196            '__function__',
197            '__line__',
198            '__method__',
199            '__namespace__',
200            '__trait__'
201        ];
202
203        return in_array(strtolower($word), $_list);
204    }
205
206    /**
207     * Whether an ID is a valid PHP identifier.
208     *
209     * @param   string  $id    ID.
210     * @return  bool
211     */
212    public static function isIdentifier($id)
213    {
214        return 0 !== preg_match(
215            '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#',
216            $id
217        );
218    }
219
220    /**
221     * Register a register shutdown function.
222     * It may be analogous to a super static destructor.
223     *
224     * @param   callable  $callable    Callable.
225     * @return  bool
226     */
227    public static function registerShutdownFunction($callable)
228    {
229        return register_shutdown_function($callable);
230    }
231
232    /**
233     * Get PHP executable.
234     *
235     * @return  string
236     */
237    public static function getPHPBinary()
238    {
239        if (defined('PHP_BINARY')) {
240            return PHP_BINARY;
241        }
242
243        if (isset($_SERVER['_'])) {
244            return $_SERVER['_'];
245        }
246
247        foreach (['', '.exe'] as $extension) {
248            if (file_exists($_ = PHP_BINDIR . DS . 'php' . $extension)) {
249                return realpath($_);
250            }
251        }
252
253        return null;
254    }
255
256    /**
257     * Generate an Universal Unique Identifier (UUID).
258     *
259     * @return  string
260     */
261    public static function uuid()
262    {
263        return sprintf(
264            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
265            mt_rand(0, 0xffff),
266            mt_rand(0, 0xffff),
267            mt_rand(0, 0xffff),
268            mt_rand(0, 0x0fff) | 0x4000,
269            mt_rand(0, 0x3fff) | 0x8000,
270            mt_rand(0, 0xffff),
271            mt_rand(0, 0xffff),
272            mt_rand(0, 0xffff)
273        );
274    }
275}
276
277}
278
279namespace
280{
281
282if (70000 > PHP_VERSION_ID && false === interface_exists('Throwable', false)) {
283    /**
284     * Implement a fake Throwable class, introduced in PHP7.0.
285     */
286    interface Throwable
287    {
288        public function getMessage();
289        public function getCode();
290        public function getFile();
291        public function getLine();
292        public function getTrace();
293        public function getPrevious();
294        public function getTraceAsString();
295        public function __toString();
296    }
297}
298
299/**
300 * Define TLSv* constants, introduced in PHP 5.5.
301 */
302if (50600 > PHP_VERSION_ID) {
303    $define = function ($constantName, $constantValue, $case = false) {
304        if (!defined($constantName)) {
305            return define($constantName, $constantValue, $case);
306        }
307
308        return false;
309    };
310
311    $define('STREAM_CRYPTO_METHOD_TLSv1_0_SERVER', 8);
312    $define('STREAM_CRYPTO_METHOD_TLSv1_1_SERVER', 16);
313    $define('STREAM_CRYPTO_METHOD_TLSv1_2_SERVER', 32);
314    $define('STREAM_CRYPTO_METHOD_ANY_SERVER', 62);
315
316    $define('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT', 9);
317    $define('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT', 17);
318    $define('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT', 33);
319    $define('STREAM_CRYPTO_METHOD_ANY_CLIENT', 63);
320}
321
322if (!function_exists('curry')) {
323    /**
324     * Curry.
325     * Example:
326     *     $c = curry('str_replace', …, …, 'foobar');
327     *     var_dump($c('foo', 'baz')); // bazbar
328     *     $c = curry('str_replace', 'foo', 'baz', …);
329     *     var_dump($c('foobarbaz')); // bazbarbaz
330     * Nested curries also work:
331     *     $c1 = curry('str_replace', …, …, 'foobar');
332     *     $c2 = curry($c1, 'foo', …);
333     *     var_dump($c2('baz')); // bazbar
334     * Obviously, as the first argument is a callable, we can combine this with
335     * \Hoa\Consistency\Xcallable ;-).
336     * The “…” character is the HORIZONTAL ELLIPSIS Unicode character (Unicode:
337     * 2026, UTF-8: E2 80 A6).
338     *
339     * @param   mixed  $callable    Callable (two parts).
340     * @param   ...    ...          Arguments.
341     * @return  \Closure
342     */
343    function curry($callable)
344    {
345        $arguments = func_get_args();
346        array_shift($arguments);
347        $ii        = array_keys($arguments, …, true);
348
349        return function () use ($callable, $arguments, $ii) {
350            return call_user_func_array(
351                $callable,
352                array_replace($arguments, array_combine($ii, func_get_args()))
353            );
354        };
355    }
356}
357
358/**
359 * Flex entity.
360 */
361Hoa\Consistency\Consistency::flexEntity('Hoa\Consistency\Consistency');
362
363}
364