Complex classes like Doku_Cli_Opts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Doku_Cli_Opts, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 73 | class Doku_Cli_Opts { |
||
| 74 | |||
| 75 | /** |
||
| 76 | * <?php ?> |
||
| 77 | * @see http://www.sitepoint.com/article/php-command-line-1/3 |
||
| 78 | * @param string $bin_file executing file name - this MUST be passed the __FILE__ constant |
||
| 79 | * @param string $short_options short options |
||
| 80 | * @param array $long_options (optional) long options |
||
| 81 | * @return Doku_Cli_Opts_Container|Doku_Cli_Opts_Error |
||
| 82 | */ |
||
| 83 | function & getOptions($bin_file, $short_options, $long_options = null) { |
||
| 84 | $args = Doku_Cli_Opts::readPHPArgv(); |
||
| 85 | |||
| 86 | if ( Doku_Cli_Opts::isError($args) ) { |
||
| 87 | return $args; |
||
| 88 | } |
||
| 89 | |||
| 90 | // Compatibility between "php extensions.php" and "./extensions.php" |
||
| 91 | if ( realpath($_SERVER['argv'][0]) == $bin_file ) { |
||
| 92 | $options = Doku_Cli_Opts::getOpt($args,$short_options,$long_options); |
||
| 93 | } else { |
||
| 94 | $options = Doku_Cli_Opts::getOpt2($args,$short_options,$long_options); |
||
| 95 | } |
||
| 96 | |||
| 97 | if ( Doku_Cli_Opts::isError($options) ) { |
||
| 98 | return $options; |
||
| 99 | } |
||
| 100 | |||
| 101 | $container = new Doku_Cli_Opts_Container($options); |
||
| 102 | return $container; |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * Parses the command-line options. |
||
| 107 | * |
||
| 108 | * The first parameter to this function should be the list of command-line |
||
| 109 | * arguments without the leading reference to the running program. |
||
| 110 | * |
||
| 111 | * The second parameter is a string of allowed short options. Each of the |
||
| 112 | * option letters can be followed by a colon ':' to specify that the option |
||
| 113 | * requires an argument, or a double colon '::' to specify that the option |
||
| 114 | * takes an optional argument. |
||
| 115 | * |
||
| 116 | * The third argument is an optional array of allowed long options. The |
||
| 117 | * leading '--' should not be included in the option name. Options that |
||
| 118 | * require an argument should be followed by '=', and options that take an |
||
| 119 | * option argument should be followed by '=='. |
||
| 120 | * |
||
| 121 | * The return value is an array of two elements: the list of parsed |
||
| 122 | * options and the list of non-option command-line arguments. Each entry in |
||
| 123 | * the list of parsed options is a pair of elements - the first one |
||
| 124 | * specifies the option, and the second one specifies the option argument, |
||
| 125 | * if there was one. |
||
| 126 | * |
||
| 127 | * Long and short options can be mixed. |
||
| 128 | * |
||
| 129 | * Most of the semantics of this function are based on GNU getopt_long(). |
||
| 130 | * |
||
| 131 | * @param array $args an array of command-line arguments |
||
| 132 | * @param string $short_options specifies the list of allowed short options |
||
| 133 | * @param array $long_options specifies the list of allowed long options |
||
| 134 | * |
||
| 135 | * @return array two-element array containing the list of parsed options and |
||
| 136 | * the non-option arguments |
||
| 137 | * @access public |
||
| 138 | */ |
||
| 139 | function getopt2($args, $short_options, $long_options = null) { |
||
| 140 | return Doku_Cli_Opts::doGetopt( |
||
| 141 | 2, $args, $short_options, $long_options |
||
| 142 | ); |
||
| 143 | } |
||
| 144 | |||
| 145 | /** |
||
| 146 | * This function expects $args to start with the script name (POSIX-style). |
||
| 147 | * Preserved for backwards compatibility. |
||
| 148 | * |
||
| 149 | * @param array $args an array of command-line arguments |
||
| 150 | * @param string $short_options specifies the list of allowed short options |
||
| 151 | * @param array $long_options specifies the list of allowed long options |
||
| 152 | * |
||
| 153 | * @see getopt2() |
||
| 154 | * @return array two-element array containing the list of parsed options and |
||
| 155 | * the non-option arguments |
||
| 156 | */ |
||
| 157 | function getopt($args, $short_options, $long_options = null) { |
||
| 158 | return Doku_Cli_Opts::doGetopt( |
||
| 159 | 1, $args, $short_options, $long_options |
||
| 160 | ); |
||
| 161 | } |
||
| 162 | |||
| 163 | /** |
||
| 164 | * The actual implementation of the argument parsing code. |
||
| 165 | * |
||
| 166 | * @param int $version Version to use |
||
| 167 | * @param array $args an array of command-line arguments |
||
| 168 | * @param string $short_options specifies the list of allowed short options |
||
| 169 | * @param array $long_options specifies the list of allowed long options |
||
| 170 | * |
||
| 171 | * @return array |
||
| 172 | */ |
||
| 173 | function doGetopt($version, $args, $short_options, $long_options = null) { |
||
| 174 | |||
| 175 | // in case you pass directly readPHPArgv() as the first arg |
||
| 176 | if (Doku_Cli_Opts::isError($args)) { |
||
| 177 | return $args; |
||
| 178 | } |
||
| 179 | if (empty($args)) { |
||
| 180 | return array(array(), array()); |
||
| 181 | } |
||
| 182 | $opts = array(); |
||
| 183 | $non_opts = array(); |
||
| 184 | |||
| 185 | settype($args, 'array'); |
||
| 186 | |||
| 187 | if ($long_options && is_array($long_options)) { |
||
| 188 | sort($long_options); |
||
| 189 | } |
||
| 190 | |||
| 191 | /* |
||
| 192 | * Preserve backwards compatibility with callers that relied on |
||
| 193 | * erroneous POSIX fix. |
||
| 194 | */ |
||
| 195 | if ($version < 2) { |
||
| 196 | if (isset($args[0]{0}) && $args[0]{0} != '-') { |
||
| 197 | array_shift($args); |
||
| 198 | } |
||
| 199 | } |
||
| 200 | |||
| 201 | reset($args); |
||
| 202 | while (list($i, $arg) = each($args)) { |
||
| 203 | |||
| 204 | /* The special element '--' means explicit end of |
||
| 205 | options. Treat the rest of the arguments as non-options |
||
| 206 | and end the loop. */ |
||
| 207 | if ($arg == '--') { |
||
| 208 | $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); |
||
| 209 | break; |
||
| 210 | } |
||
| 211 | |||
| 212 | if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { |
||
| 213 | $non_opts = array_merge($non_opts, array_slice($args, $i)); |
||
| 214 | break; |
||
| 215 | } elseif (strlen($arg) > 1 && $arg{1} == '-') { |
||
| 216 | $error = Doku_Cli_Opts::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); |
||
| 217 | if (Doku_Cli_Opts::isError($error)) |
||
| 218 | return $error; |
||
| 219 | } elseif ($arg == '-') { |
||
| 220 | // - is stdin |
||
| 221 | $non_opts = array_merge($non_opts, array_slice($args, $i)); |
||
| 222 | break; |
||
| 223 | } else { |
||
| 224 | $error = Doku_Cli_Opts::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); |
||
| 225 | if (Doku_Cli_Opts::isError($error)) |
||
| 226 | return $error; |
||
| 227 | } |
||
| 228 | } |
||
| 229 | |||
| 230 | return array($opts, $non_opts); |
||
| 231 | } |
||
| 232 | |||
| 233 | /** |
||
| 234 | * Parse short option |
||
| 235 | * |
||
| 236 | * @param string $arg Argument |
||
| 237 | * @param string $short_options Available short options |
||
| 238 | * @param string[][] &$opts |
||
| 239 | * @param string[] &$args |
||
| 240 | * |
||
| 241 | * @access private |
||
| 242 | * @return void|Doku_Cli_Opts_Error |
||
| 243 | */ |
||
| 244 | function _parseShortOption($arg, $short_options, &$opts, &$args) { |
||
| 245 | $len = strlen($arg); |
||
| 246 | for ($i = 0; $i < $len; $i++) { |
||
| 247 | $opt = $arg{$i}; |
||
| 248 | $opt_arg = null; |
||
| 249 | |||
| 250 | /* Try to find the short option in the specifier string. */ |
||
| 251 | if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') |
||
| 252 | { |
||
| 253 | return Doku_Cli_Opts::raiseError( |
||
| 254 | DOKU_CLI_OPTS_UNKNOWN_OPT, |
||
| 255 | "Unrecognized option -- $opt" |
||
| 256 | ); |
||
| 257 | } |
||
| 258 | |||
| 259 | if (strlen($spec) > 1 && $spec{1} == ':') { |
||
| 260 | if (strlen($spec) > 2 && $spec{2} == ':') { |
||
| 261 | if ($i + 1 < strlen($arg)) { |
||
| 262 | /* Option takes an optional argument. Use the remainder of |
||
| 263 | the arg string if there is anything left. */ |
||
| 264 | $opts[] = array($opt, substr($arg, $i + 1)); |
||
| 265 | break; |
||
| 266 | } |
||
| 267 | } else { |
||
| 268 | /* Option requires an argument. Use the remainder of the arg |
||
| 269 | string if there is anything left. */ |
||
| 270 | if ($i + 1 < strlen($arg)) { |
||
| 271 | $opts[] = array($opt, substr($arg, $i + 1)); |
||
| 272 | break; |
||
| 273 | } else if (list(, $opt_arg) = each($args)) { |
||
| 274 | /* Else use the next argument. */; |
||
| 275 | if (Doku_Cli_Opts::_isShortOpt($opt_arg) || Doku_Cli_Opts::_isLongOpt($opt_arg)) |
||
| 276 | return Doku_Cli_Opts::raiseError( |
||
| 277 | DOKU_CLI_OPTS_OPT_ARG_REQUIRED, |
||
| 278 | "option requires an argument --$opt" |
||
| 279 | ); |
||
| 280 | } |
||
| 281 | else |
||
| 282 | return Doku_Cli_Opts::raiseError( |
||
| 283 | DOKU_CLI_OPTS_OPT_ARG_REQUIRED, |
||
| 284 | "Option requires an argument -- $opt" |
||
| 285 | ); |
||
| 286 | } |
||
| 287 | } |
||
| 288 | |||
| 289 | $opts[] = array($opt, $opt_arg); |
||
| 290 | } |
||
| 291 | } |
||
| 292 | |||
| 293 | /** |
||
| 294 | * Checks if an argument is a short option |
||
| 295 | * |
||
| 296 | * @param string $arg Argument to check |
||
| 297 | * |
||
| 298 | * @access private |
||
| 299 | * @return bool |
||
| 300 | */ |
||
| 301 | function _isShortOpt($arg){ |
||
| 305 | |||
| 306 | /** |
||
| 307 | * Checks if an argument is a long option |
||
| 308 | * |
||
| 309 | * @param string $arg Argument to check |
||
| 310 | * |
||
| 311 | * @access private |
||
| 312 | * @return bool |
||
| 313 | */ |
||
| 314 | function _isLongOpt($arg){ |
||
| 318 | |||
| 319 | /** |
||
| 320 | * Parse long option |
||
| 321 | * |
||
| 322 | * @param string $arg Argument |
||
| 323 | * @param string[] $long_options Available long options |
||
| 324 | * @param string[][] &$opts |
||
| 325 | * @param string[] &$args |
||
| 326 | * |
||
| 327 | * @access private |
||
| 328 | * @return void|Doku_Cli_Opts_Error |
||
| 329 | */ |
||
| 330 | function _parseLongOption($arg, $long_options, &$opts, &$args) { |
||
| 331 | @list($opt, $opt_arg) = explode('=', $arg, 2); |
||
|
1 ignored issue
–
show
|
|||
| 332 | $opt_len = strlen($opt); |
||
| 333 | $opt_cnt = count($long_options); |
||
| 334 | |||
| 335 | for ($i = 0; $i < $opt_cnt; $i++) { |
||
| 336 | $long_opt = $long_options[$i]; |
||
| 337 | $opt_start = substr($long_opt, 0, $opt_len); |
||
| 338 | |||
| 339 | $long_opt_name = str_replace('=', '', $long_opt); |
||
| 340 | |||
| 341 | /* Option doesn't match. Go on to the next one. */ |
||
| 342 | if ($opt_start != $opt) |
||
| 343 | continue; |
||
| 344 | |||
| 345 | $opt_rest = substr($long_opt, $opt_len); |
||
| 346 | |||
| 347 | /* Check that the options uniquely matches one of the allowed |
||
| 348 | options. */ |
||
| 349 | if ($i + 1 < count($long_options)) { |
||
| 350 | $next_option_rest = substr($long_options[$i + 1], $opt_len); |
||
| 351 | } else { |
||
| 352 | $next_option_rest = ''; |
||
| 353 | } |
||
| 354 | |||
| 355 | if ($opt_rest != '' && $opt{0} != '=' && |
||
| 356 | $i + 1 < $opt_cnt && |
||
| 357 | $opt == substr($long_options[$i+1], 0, $opt_len) && |
||
| 358 | $next_option_rest != '' && |
||
| 359 | $next_option_rest{0} != '=') { |
||
| 360 | return Doku_Cli_Opts::raiseError( |
||
| 361 | DOKU_CLI_OPTS_OPT_ABIGUOUS, |
||
| 362 | "Option --$opt is ambiguous" |
||
| 363 | ); |
||
| 364 | } |
||
| 365 | |||
| 366 | if (substr($long_opt, -1) == '=') { |
||
| 367 | if (substr($long_opt, -2) != '==') { |
||
| 368 | /* Long option requires an argument. |
||
| 369 | Take the next argument if one wasn't specified. */; |
||
| 370 | if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { |
||
| 371 | return Doku_Cli_Opts::raiseError( |
||
| 372 | DOKU_CLI_OPTS_OPT_ARG_REQUIRED, |
||
| 373 | "Option --$opt requires an argument" |
||
| 374 | ); |
||
| 375 | } |
||
| 376 | |||
| 377 | if (Doku_Cli_Opts::_isShortOpt($opt_arg) |
||
| 378 | || Doku_Cli_Opts::_isLongOpt($opt_arg)) |
||
| 379 | return Doku_Cli_Opts::raiseError( |
||
| 380 | DOKU_CLI_OPTS_OPT_ARG_REQUIRED, |
||
| 381 | "Option --$opt requires an argument" |
||
| 382 | ); |
||
| 383 | } |
||
| 384 | } else if ($opt_arg) { |
||
| 385 | return Doku_Cli_Opts::raiseError( |
||
| 386 | DOKU_CLI_OPTS_OPT_ARG_DENIED, |
||
| 387 | "Option --$opt doesn't allow an argument" |
||
| 388 | ); |
||
| 389 | } |
||
| 390 | |||
| 391 | $opts[] = array('--' . $opt, $opt_arg); |
||
| 392 | return; |
||
| 393 | } |
||
| 394 | |||
| 395 | return Doku_Cli_Opts::raiseError( |
||
| 396 | DOKU_CLI_OPTS_UNKNOWN_OPT, |
||
| 397 | "Unrecognized option --$opt" |
||
| 398 | ); |
||
| 399 | } |
||
| 400 | |||
| 401 | /** |
||
| 402 | * Safely read the $argv PHP array across different PHP configurations. |
||
| 403 | * Will take care on register_globals and register_argc_argv ini directives |
||
| 404 | * |
||
| 405 | * @access public |
||
| 406 | * @return array|Doku_Cli_Opts_Error the $argv PHP array or PEAR error if not registered |
||
| 407 | */ |
||
| 408 | function readPHPArgv() { |
||
| 424 | |||
| 425 | /** |
||
| 426 | * @param $code |
||
| 427 | * @param $msg |
||
| 428 | * @return Doku_Cli_Opts_Error |
||
| 429 | */ |
||
| 430 | function raiseError($code, $msg) { |
||
| 433 | |||
| 434 | /** |
||
| 435 | * @param $obj |
||
| 436 | * @return bool |
||
| 437 | */ |
||
| 438 | function isError($obj) { |
||
| 441 | |||
| 442 | } |
||
| 443 | |||
| 444 | //------------------------------------------------------------------------------ |
||
| 445 | class Doku_Cli_Opts_Error { |
||
| 446 | |||
| 447 | var $code; |
||
| 513 |
If you suppress an error, we recommend checking for the error condition explicitly: