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