Passed
Push — master ( e2ab55...13b777 )
by Akpé Aurelle Emmanuel Moïse
02:15
created

Shortcut::SetShortcutForAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace EZAMA
3
4
/**
5
*
6
* @Name : Shortcut
7
* @Version : 1.0.0
8
* @Programmer : Akpé Aurelle Emmanuel Moïse Zinsou
9
* @Date : 2019-04-01
10
* @Released under : https://github.com/manuwhat/Shortcut/blob/master/LICENSE
11
* @Repository : https://github.com/manuwhat/Shortcut
12
*
13
**/
14
{
15
16
    class Shortcut
17
    {
18
        const VALID_PHP_FUNCTION_NAME_PATTERN='#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#';
19
        const CAN_NEVER_EVER_CHOOSE_THIS_AS_FUNCTION_NAME="new";
20
        const PLACEHOLDER_FOR_INTERNALS_CLASSES_OPTIONALS_PARAMETERS="acce91966cd8eee995ee1ac30c98c3d89d8f9235";
21
        private static $DIR=null;
22
        private static $SHORTCUT_FOR_ALL=false;
23
        
24
        public static function SetShortcutForAll($bool)
25
        {
26
            self::$SHORTCUT_FOR_ALL=(bool)$bool;
27
        }
28
        public static function create($classname, $name=self::CAN_NEVER_EVER_CHOOSE_THIS_AS_FUNCTION_NAME)
29
        {
30
            if (is_string($classname)&&class_exists($classname, true)) {
31
                $reflectionClass=new \reflectionClass($classname);
32
                $classname=$reflectionClass->getName();
33
                $fullQualifiedClassname=str_replace('\\', '_', $classname);
34
                self::getTheRightDir($file, $Dir, $fullQualifiedClassname);
35
                $fileExists=file_exists($file);
36
                if (!function_exists($classname)&&!function_exists($name)) {
37
                    if (!$fileExists) {
38
                        $private_scope=false;
39
                        $name=trim($name);
40
                        self::createDir($Dir);
41
                        $reflectionMethod=$reflectionClass->getConstructor();
42
                        $notInstantiable=false;
43
                        if (is_null($reflectionMethod)||$notInstantiable=!$reflectionClass->isInstantiable()) {
44
                            self::HandleNotInstantiableAndHasNoConstructor($Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $file, $classname);
45
                            if ($Shortcut) {
46
                                return self::pushAndShow($file, $Shortcut);
47
                            }
48
                            $private_scope=true;
49
                        }
50
                        
51
                        self::getSignature($reflectionMethod, $signature, $parameters, $paramsNum, $count);
52
                        
53
                        $hasInternal='';
54
                        if ($count) {
55
                            self::BuildTheSwitch($hasInternal, $count, $paramsNum, $parameters, $classname);
56
                        }
57
                        self::useTheRightNameAndScope($Shortcut, $name, $fullQualifiedClassname, $signature, $private_scope, $classname);
58
                        
59
                        self::handleInternals($Shortcut, $hasInternal, $parameters, $signature, $classname);
60
                            
61
                        return self::pushAndShow($file, $Shortcut);
62
                    } else {
63
                        return include_once($file);
64
                    }
65
                } else {
66
                    self::GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname);
67
                }
68
            }
69
        }
70
71
        private static function getSignature(\ReflectionMethod $method, &$signature, &$parameters, &$paramsNum, &$count)
72
        {
73
            $params=$method->getParameters();
74
            $paramsNum=count($params);
75
            $signature='';
76
            $parameters=array();
77
            $count=0;
78
            foreach ($params as $k=>$param) {
79
                if ($param->isPassedByReference()) {
80
                    $tmp='&$'.$param->getName();
81
                } else {
82
                    $tmp='$'.$param->getName();
83
                }
84
85
                if ($param->isOptional()) {
86
                    $count++;
87
                    if ($method->isInternal()) {
88
                        $tmp.='="acce91966cd8eee995ee1ac30c98c3d89d8f9235"';
89
                    } elseif ($param->isDefaultValueConstant()) {
90
                        $tmp.='='.$param->getDefaultValueConstantName();
91
                    } elseif ($param->isDefaultValueAvailable()) {
92
                        $tmp.='='.var_export($param->getDefaultValue(), true);
93
                    } elseif ($param->allowsNull()) {
94
                        $tmp.='=null';
95
                    }
96
                }
97
                
98
                $signature.=$tmp;
99
                $parameters[]='$'.$param->getName();
100
                $tmp='';
101
                if ($k<$paramsNum-1) {
102
                    $signature.=',';
103
                }
104
            }
105
        }
106
        private static function BuildTheSwitch(&$hasInternal, $count, $paramsNum, $parameters, $classname)
107
        {
108
            $hasInternal.='switch($count){';
109
            while ($count>0) {
110
                $hasInternal.="case $count:return new $classname(".join(',', array_slice($parameters, 0, $paramsNum-$count))."); break;";
111
                $count--;
112
            }
113
            $hasInternal.='default:return new '.$classname.'('.join(',', $parameters).');break;}';
114
        }
115
        
116
        private static function useTheRightNameAndScope(&$Shortcut, $name, $fullQualifiedClassname, $signature, $scope, $classname)
117
        {
118
            if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
119
                $Shortcut="<?php
120
							function $name($signature){";
121
                if ($scope) {
122
                    $Shortcut.="if(".'@get_class()'."!==$classname){
123
									throw new scopeException(\"Shortcut function $name can only be called in class $classname scope\");
124
								}";
125
                }
126
            } else {
127
                $Shortcut="<?php
128
							function $fullQualifiedClassname($signature){";
129
                if ($scope) {
130
                    $Shortcut.="if(@get_class()!==\"$classname\"){
131
							throw new scopeException(\"Shortcut function $fullQualifiedClassname can only be called in class $classname scope\");
132
						}";
133
                }
134
            }
135
        }
136
        
137
        private static function handleInternals(&$Shortcut, $hasInternal, $parameters, $signature, $classname)
138
        {
139
            if (!strpos($signature, "acce91966cd8eee995ee1ac30c98c3d89d8f9235")) {
140
                $Shortcut.="return new $classname(".join(',', $parameters).");
141
							}";
142
            } else {
143
                $Shortcut.='
144
							$count=count(array_keys(get_defined_vars(),"'.self::PLACEHOLDER_FOR_INTERNALS_CLASSES_OPTIONALS_PARAMETERS.'"));
145
							'.$hasInternal.'
146
							}';
147
            }
148
        }
149
        
150
        private static function pushAndShow($file, $Shortcut)
151
        {
152
            file_put_contents($file, str_replace("\t", '    ', $Shortcut));
153
            file_put_contents($file, php_strip_whitespace($file)); //just for cleanliness of the generated code
154
            return include_once($file);
155
        }
156
        
157
        private static function GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname)
158
        {
159
            if (!$fileExists) {
160
                if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
161
                    throw new \InvalidArgumentException('function '.$name.' passed as second Argument already exists.
162
					Can\'t create a shortcut with the same name');
163
                } else {
164
                    throw new \InvalidArgumentException('function '.$fullQualifiedClassname.' already exists and An alias has not been provided as Argument 2.
165
					Can\'t create a shortcut function with this name');
166
                }
167
            }
168
        }
169
        
170
        private static function HandleNotInstantiableAndHasNoConstructor(&$Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $file, $classname)
0 ignored issues
show
Unused Code introduced by
The parameter $file is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

170
        private static function HandleNotInstantiableAndHasNoConstructor(&$Shortcut, $fullQualifiedClassname, $name, $notInstantiable, /** @scrutinizer ignore-unused */ $file, $classname)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
171
        {
172
            if ($notInstantiable) {
173
                if (!self::$SHORTCUT_FOR_ALL) {
174
                    throw new \InvalidArgumentException('Not Instantiable class '.$fullQualifiedClassname.' passed as Argument');
175
                }
176
            } else {
177
                self::useTheRightNameAndScope($Shortcut, $name, $fullQualifiedClassname, '', false, $classname);
178
                $Shortcut.="return new $classname();
179
						}";
180
                // return self::pushAndShow($file, $Shortcut);
181
            }
182
        }
183
        
184
        private static function getTheRightDir(&$file, &$Dir, $fullQualifiedClassname)
185
        {
186
            if ($Dir=self::$DIR) {
187
                $file=self::$DIR.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
188
            } else {
189
                $Dir=dirname(__DIR__).DIRECTORY_SEPARATOR.'ClassShortcuts';
190
                $file=$Dir.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
191
            }
192
        }
193
        
194
        private static function createDir($Dir)
195
        {
196
            if (!file_exists($Dir)) {
197
                mkdir($Dir);
198
            }
199
        }
200
        
201
        
202
        
203
        public static function setDir($dirname)
204
        {
205
            if (is_dir($dirname)&&is_writable($dirname)&&!self::$DIR) {
206
                self::$DIR=$dirname;
207
            }
208
        }
209
        
210
        
211
        private function __construct()
212
        {
213
        }
214
    }
215
    
216
    
217
}
218
219
namespace{
220
    function create_Shortcut($classname, $name='new')
221
    {
222
        return EZAMA\Shortcut::create($classname, $name);
223
    }
224
    class scopeException extends \Exception
225
    {
226
    }
227
}
228