Passed
Push — master ( 3cb13d...a86dde )
by Akpé Aurelle Emmanuel Moïse
01:58
created

Shortcut::BuildCacheAndShow()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 10
dl 0
loc 11
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
                return self::_create($classname, $name);
32
            }
33
        }
34
        
35
        private static function _init($classname)
36
        {
37
            return [
38
                'reflectionClass'=>$tmp=new \reflectionClass($classname),
39
                'classname'=>$tmp->getName(),
40
                'fullQualifiedClassname'=>str_replace('\\', '_', $classname),
41
            ];
42
        }
43
        
44
        private static function forwardInit($name, $Dir, \reflectionClass $reflectionClass)
45
        {
46
            self::createDir($Dir);
47
            return [
48
                'private_scope'=>false,
49
                'name'=>trim($name),
50
                'reflectionMethod'=>$reflectionClass->getConstructor(),
51
                'notInstantiable'=>false,
52
            ];
53
        }
54
        
55
        private static function _create($classname, $name)
56
        {
57
            extract(self::_init($classname));
58
            self::getTheRightDir($file, $Dir, $fullQualifiedClassname);
59
            $fileExists=file_exists($file);
60
            if (!function_exists($classname)&&!function_exists($name)) {
61
                return self::handleNewShortcut($classname, $name, $file, $Dir, $fullQualifiedClassname, $fileExists, $reflectionClass);
62
            } else {
63
                self::GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname);
64
            }
65
        }
66
        
67
        private static function handleNewShortcut($classname, $name, $file, $Dir, $fullQualifiedClassname, $fileExists, \reflectionClass $reflectionClass)
68
        {
69
            if ($fileExists) {
70
                return include_once($file);
71
            }
72
            extract(self::forwardInit($name, $Dir, $reflectionClass));
73
            if (is_null($reflectionMethod)||$notInstantiable=!$reflectionClass->isInstantiable()) {
74
                self::HandleNotInstantiableAndHasNoConstructor($Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $classname);
75
                if ($Shortcut) {
76
                    return self::pushAndShow($file, $Shortcut);
77
                }
78
                $private_scope=true;
79
            }
80
81
            return  self::BuildCacheAndShow($classname,$name,$file,$Dir,$fullQualifiedClassname,$fileExists,$reflectionClass,$reflectionMethod,$notInstantiable,$private_scope);      
82
           
83
        }
84
		
85
		private static function BuildCacheAndShow($classname,$name,$file,$Dir,$fullQualifiedClassname,$fileExists,$reflectionClass,$reflectionMethod,$notInstantiable,$private_scope){
0 ignored issues
show
Unused Code introduced by
The parameter $reflectionClass 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

85
		private static function BuildCacheAndShow($classname,$name,$file,$Dir,$fullQualifiedClassname,$fileExists,/** @scrutinizer ignore-unused */ $reflectionClass,$reflectionMethod,$notInstantiable,$private_scope){

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...
Unused Code introduced by
The parameter $notInstantiable 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

85
		private static function BuildCacheAndShow($classname,$name,$file,$Dir,$fullQualifiedClassname,$fileExists,$reflectionClass,$reflectionMethod,/** @scrutinizer ignore-unused */ $notInstantiable,$private_scope){

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...
Unused Code introduced by
The parameter $Dir 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

85
		private static function BuildCacheAndShow($classname,$name,$file,/** @scrutinizer ignore-unused */ $Dir,$fullQualifiedClassname,$fileExists,$reflectionClass,$reflectionMethod,$notInstantiable,$private_scope){

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...
Unused Code introduced by
The parameter $fileExists 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

85
		private static function BuildCacheAndShow($classname,$name,$file,$Dir,$fullQualifiedClassname,/** @scrutinizer ignore-unused */ $fileExists,$reflectionClass,$reflectionMethod,$notInstantiable,$private_scope){

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...
86
			self::getSignature($reflectionMethod, $signature, $parameters, $paramsNum, $count);        
87
            $hasInternal='';
88
            if ($count) {
89
                self::BuildTheSwitch($hasInternal, $count, $paramsNum, $parameters, $classname);
90
            }
91
            self::useTheRightNameAndScope($Shortcut, $name, $fullQualifiedClassname, $signature, $private_scope, $classname);
92
                    
93
            self::handleInternals($Shortcut, $hasInternal, $parameters, $signature, $classname);
94
                        
95
            return self::pushAndShow($file, $Shortcut);
96
		}
97
98
        private static function getSignature(\ReflectionMethod $method, &$signature, &$parameters, &$paramsNum, &$count)
99
        {
100
            $params=$method->getParameters();
101
            $paramsNum=count($params);
102
            $signature='';
103
            $parameters=array();
104
            $count=0;
105
            foreach ($params as $k=>$param) {
106
                self::getParameterDeclaration($param, $tmp, $count, $method);
107
                $signature.=$tmp;
108
                $parameters[]='$'.$param->getName();
109
                $tmp='';
110
                if ($k<$paramsNum-1) {
111
                    $signature.=',';
112
                }
113
            }
114
        }
115
        
116
        private static function getParameterDeclaration(\reflectionParameter $param, &$tmp, &$count, $method)
117
        {
118
            $tmp=$param->isPassedByReference()?'&$'.$param->getName():'$'.$param->getName();
119
            if ($param->isOptional()) {
120
                $count++;
121
                if ($method->isInternal()) {
122
                    $tmp.='="acce91966cd8eee995ee1ac30c98c3d89d8f9235"';
123
                } else {
124
                    self::handleOptionalParameter($param, $tmp);
125
                }
126
            }
127
        }
128
        
129
        private static function handleOptionalParameter(\reflectionParameter $param, &$tmp)
130
        {
131
            if ($param->isDefaultValueConstant()) {
132
                $tmp.='='.$param->getDefaultValueConstantName();
133
            } elseif ($param->isDefaultValueAvailable()) {
134
                $tmp.='='.var_export($param->getDefaultValue(), true);
135
            } elseif ($param->allowsNull()) {
136
                $tmp.='=null';
137
            }
138
        }
139
        
140
        private static function BuildTheSwitch(&$hasInternal, $count, $paramsNum, $parameters, $classname)
141
        {
142
            $hasInternal.='switch($count){';
143
            while ($count>0) {
144
                $hasInternal.="case $count:return new $classname(".join(',', array_slice($parameters, 0, $paramsNum-$count))."); break;";
145
                $count--;
146
            }
147
            $hasInternal.='default:return new '.$classname.'('.join(',', $parameters).');break;}';
148
        }
149
        
150
        private static function useTheRightNameAndScope(&$Shortcut, $name, $fullQualifiedClassname, $signature, $scope, $classname)
151
        {
152
            if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
153
                $Shortcut="<?php
154
							function $name($signature){";
155
                if ($scope) {
156
                    $Shortcut.="if(".'@get_class()'."!==$classname){
157
									throw new scopeException(\"Shortcut function $name can only be called in class $classname scope\");
158
								}";
159
                }
160
            } else {
161
                $Shortcut="<?php
162
							function $fullQualifiedClassname($signature){";
163
                if ($scope) {
164
                    $Shortcut.="if(@get_class()!==\"$classname\"){
165
							throw new scopeException(\"Shortcut function $fullQualifiedClassname can only be called in class $classname scope\");
166
						}";
167
                }
168
            }
169
        }
170
        
171
        private static function handleInternals(&$Shortcut, $hasInternal, $parameters, $signature, $classname)
172
        {
173
            if (!strpos($signature, "acce91966cd8eee995ee1ac30c98c3d89d8f9235")) {
174
                $Shortcut.="return new $classname(".join(',', $parameters).");
175
							}";
176
            } else {
177
                $Shortcut.='
178
							$count=count(array_keys(get_defined_vars(),"'.self::PLACEHOLDER_FOR_INTERNALS_CLASSES_OPTIONALS_PARAMETERS.'"));
179
							'.$hasInternal.'
180
							}';
181
            }
182
        }
183
        
184
        private static function pushAndShow($file, $Shortcut)
185
        {
186
            file_put_contents($file, str_replace("\t", '    ', $Shortcut));
187
            file_put_contents($file, php_strip_whitespace($file)); //just for cleanliness of the generated code
188
            return include_once($file);
189
        }
190
        
191
        private static function GetTheRightExceptionMessage($fileExists, $name, $fullQualifiedClassname)
192
        {
193
            if (!$fileExists) {
194
                if (strtolower($name)!=='new'&&preg_match(self::VALID_PHP_FUNCTION_NAME_PATTERN, $name)) {
195
                    throw new \InvalidArgumentException('function '.$name.' passed as second Argument already exists.
196
					Can\'t create a shortcut with the same name');
197
                } else {
198
                    throw new \InvalidArgumentException('function '.$fullQualifiedClassname.' already exists and An alias has not been provided as Argument 2.
199
					Can\'t create a shortcut function with this name');
200
                }
201
            }
202
        }
203
        
204
        private static function HandleNotInstantiableAndHasNoConstructor(&$Shortcut, $fullQualifiedClassname, $name, $notInstantiable, $classname)
205
        {
206
            if ($notInstantiable) {
207
                if (!self::$SHORTCUT_FOR_ALL) {
208
                    throw new \InvalidArgumentException('Not Instantiable class '.$fullQualifiedClassname.' passed as Argument');
209
                }
210
            } else {
211
                self::useTheRightNameAndScope($Shortcut, $name, $fullQualifiedClassname, '', false, $classname);
212
                $Shortcut.="return new $classname();
213
						}";
214
            }
215
        }
216
        
217
        private static function getTheRightDir(&$file, &$Dir, $fullQualifiedClassname)
218
        {
219
            if ($Dir=self::$DIR) {
220
                $file=self::$DIR.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
221
            } else {
222
                $Dir=dirname(__DIR__).DIRECTORY_SEPARATOR.'ClassShortcuts';
223
                $file=$Dir.DIRECTORY_SEPARATOR.$fullQualifiedClassname.".Shortcut.php";
224
            }
225
        }
226
        
227
        private static function createDir($Dir)
228
        {
229
            if (!file_exists($Dir)) {
230
                mkdir($Dir);
231
            }
232
        }
233
        
234
        public static function setDir($dirname)
235
        {
236
            if (is_dir($dirname)&&is_writable($dirname)&&!self::$DIR) {
237
                self::$DIR=$dirname;
238
            }
239
        } 
240
        
241
        private function __construct()
242
        {
243
        }
244
    }
245
    
246
    
247
}
248
249
namespace{
250
    function create_Shortcut($classname, $name='new')
251
    {
252
        return EZAMA\Shortcut::create($classname, $name);
253
    }
254
    class scopeException extends \Exception
255
    {
256
    }
257
}
258