NamespaceBacktracerTrait::extractNamespace()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * Bright Nucleus Namespace Backtracer.
4
 *
5
 * Get the namespace of the calling object.
6
 *
7
 * @package   BrightNucleus\NamespaceBacktracer
8
 * @author    Alain Schlesser <[email protected]>
9
 * @license   MIT
10
 * @link      https://www.brightnucleus.com/
11
 * @copyright 2016 Alain Schlesser, Bright Nucleus
12
 */
13
14
namespace BrightNucleus\NamespaceBacktracer;
15
16
/**
17
 * Trait NamespaceBacktracerTrait.
18
 *
19
 * @since  0.1.0
20
 *
21
 * @author Alain Schlesser <[email protected]>
22
 */
23
trait NamespaceBacktracerTrait
24
{
25
26
    /**
27
     * Get the caller from debug_backtrace() info.
28
     *
29
     * This traverses the call stack until it finds the first function that is
30
     * not a method of an ignored class/interface.
31
     * You should pass in the output of
32
     * `debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)`.
33
     *
34
     * @since 0.1.0
35
     *
36
     * @param array|null $debugInfo Optional. Output of `debug_backtrace()` function.
37
     *
38
     * @return string Fully qualified name of the calling object/function.
39
     */
40 8
    protected function getCaller($debugInfo = null)
41
    {
42
        // Fetch the debugInfo if none was passed in.
43 8
        if ($debugInfo === null) {
44 3
            $debugInfo = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
45
        }
46
47 8
        $ignoredInterfaces = $this->getIgnoredInterfaces();
48 8
        $ignoredFunctions  = $this->getIgnoredFunctions();
49
50 8
        foreach ($debugInfo as $entry) {
51 8
            $found = false;
52
53
            // Are we dealing with a class method or a function?
54 8
            if (isset($entry['class']) && ! empty($entry['class'])) {
55 8
                $class = $entry['class'];
56
57 8
                $ignored = false;
58 8
                foreach ($ignoredInterfaces as $ignoredInterface) {
59 4
                    if ($class === $ignoredInterface) {
60 4
                        $ignored = true;
61 4
                        break;
62
                    }
63 4
                    if (is_subclass_of($class, $ignoredInterface)) {
64
                        $ignored = true;
65 4
                        break;
66
                    }
67
                }
68 8
                if (! $ignored) {
69 8
                    $found = $class;
70
                }
71
            } else {
72
                $function = $entry['function'];
73
                if (! in_array($function, $ignoredFunctions, true)) {
74
                    $found = $function;
75
                }
76
            }
77
78 8
            if (false !== $found) {
79 8
                return $found;
80
            }
81
        }
82
83
        return '';
84
    }
85
86
    /**
87
     * Get the caller's namespace from debug_backtrace() info.
88
     *
89
     * This traverses the call stack until it finds the first function that is
90
     * not a method of an ignored class/interface.
91
     * You should pass in the output of
92
     * `debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)`.
93
     *
94
     * @since 0.1.0
95
     *
96
     * @param array|null $debugInfo Optional. Output of `debug_backtrace()` function.
97
     *
98
     * @return string Namespace of the calling object.
99
     */
100 4
    protected function getCallingNamespace($debugInfo = null)
101
    {
102
        // Fetch the debugInfo if none was passed in.
103 4
        if ($debugInfo === null) {
104 3
            $debugInfo = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
105
        }
106
107 4
        $namespace = $this->extractNamespace($this->getCaller($debugInfo));
108
109 4
        return '' !== $namespace
110 2
            ? $namespace
111 4
            : $this->getGlobalNamespace();
112
    }
113
114
    /**
115
     * Extract the namespace from a fully qualified class name.
116
     *
117
     * @since 0.1.0
118
     *
119
     * @param string $class Fully qualified class name.
120
     *
121
     * @return string Namespace of the class. Empty string if none.
122
     */
123 4
    protected function extractNamespace($class)
124
    {
125 4
        $pos = strrpos($class, '\\');
126 4
        if (false === $pos) {
127 2
            return '';
128
        }
129
130 2
        return substr($class, 0, $pos);
131
    }
132
133
    /**
134
     * Get an array of interfaces/classes to ignore while fetching a namespace.
135
     *
136
     * Override this method to adapt the output to your specific environment.
137
     *
138
     * @since 0.1.0
139
     *
140
     * @return array Array of interface/class names.
141
     */
142
    protected function getIgnoredInterfaces()
143
    {
144
        return [];
145
    }
146
147
    /**
148
     * Get an array of functions to ignore while fetching a namespace.
149
     *
150
     * Override this method to adapt the output to your specific environment.
151
     *
152
     * @since 0.1.0
153
     *
154
     * @return array Array of function names.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
155
     */
156
    protected function getIgnoredFunctions()
157
    {
158
        return [
159
            'call_user_func',
160
        ];
161
    }
162
163
    /**
164
     * Get the string that is returned when the global namespace was hit.
165
     *
166
     * Override this method to adapt the output to your specific environment.
167
     *
168
     * @since 0.1.0
169
     *
170
     * @return string String that represents the global namespace.
171
     */
172
    protected function getGlobalNamespace()
173
    {
174
        return '(global)';
175
    }
176
}
177