Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 19 | class SearchCommand extends RepositoryUtilisingCommand |
||
| 20 | { |
||
| 21 | const COMMAND_NAME = 'search'; |
||
| 22 | const ARGUMENT_CODEPOINT = 'codepoint'; |
||
| 23 | const OPTION_FROM = 'from'; |
||
| 24 | const OPTION_ENCODING = 'enc'; |
||
| 25 | const ENCODING_DECIMAL = 'dec'; |
||
| 26 | const ENCODING_HEXADECIMAL = 'hex'; |
||
| 27 | const ENCODING_UTF8 = 'utf8'; |
||
| 28 | |||
| 29 | protected function configure() |
||
| 30 | { |
||
| 31 | $this->setName(self::COMMAND_NAME); |
||
| 32 | $this->setDescription('Search a character repository by codepoint'); |
||
| 33 | $this->setDefinition($this->createInputDefinition()); |
||
| 34 | } |
||
| 35 | |||
| 36 | /** |
||
| 37 | * @param InputInterface $input |
||
| 38 | * @param OutputInterface $output |
||
| 39 | * @return int |
||
| 40 | */ |
||
| 41 | protected function execute(InputInterface $input, OutputInterface $output) |
||
| 42 | { |
||
| 43 | $start = microtime(true); |
||
| 44 | $encoding = $input->getOption(self::OPTION_ENCODING); |
||
| 45 | $codepointValue = $input->getArgument(self::ARGUMENT_CODEPOINT); |
||
| 46 | $codepoint = $this->valueToCodepoint($codepointValue, $encoding); |
||
| 47 | $from = $input->getOption(self::OPTION_FROM); |
||
| 48 | $repository = $this->getRepositoryByName($from); |
||
| 49 | $db = new Database($repository); |
||
| 50 | $exporter = new Exporter(); |
||
| 51 | |||
| 52 | try { |
||
| 53 | $character = $db->getCharacterByCodepoint($codepoint); |
||
| 54 | } catch (CharacterNotFoundException $e) { |
||
| 55 | $output->writeln('<error>Character Not Found</error>'); |
||
| 56 | return 1; |
||
| 57 | } |
||
| 58 | |||
| 59 | $output->writeln('<info>Character Found</info>'); |
||
| 60 | $output->writeln(sprintf('Export: %s', $exporter->export($character))); |
||
| 61 | $output->writeln(sprintf('UTF-8: %s', $codepoint->toUTF8())); |
||
| 62 | $output->writeln(sprintf('Memory peak: %.5f MB', memory_get_peak_usage() / 1048576)); |
||
| 63 | $output->writeln(sprintf('Took: %.5f seconds', microtime(true) - $start)); |
||
| 64 | |||
| 65 | return 0; |
||
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @param string $value |
||
| 70 | * @param string $encoding |
||
| 71 | * @return Codepoint |
||
| 72 | * @throws InvalidArgumentException |
||
| 73 | */ |
||
| 74 | private function valueToCodepoint($value, $encoding) |
||
| 75 | { |
||
| 76 | if ($encoding === self::ENCODING_DECIMAL) { |
||
| 77 | return Codepoint::fromInt((int)$value); |
||
| 78 | } elseif ($encoding === self::ENCODING_HEXADECIMAL) { |
||
| 79 | return Codepoint::fromHex($value); |
||
| 80 | } elseif ($encoding === self::ENCODING_UTF8) { |
||
| 81 | return Codepoint::fromUTF8($value); |
||
| 82 | } |
||
| 83 | |||
| 84 | throw new InvalidArgumentException(sprintf('Unknown encoding: %s', $encoding)); |
||
| 85 | } |
||
| 86 | |||
| 87 | /** |
||
| 88 | * @return InputDefinition |
||
| 89 | */ |
||
| 90 | private function createInputDefinition() |
||
| 91 | { |
||
| 92 | $codepoint = new InputArgument( |
||
| 93 | self::ARGUMENT_CODEPOINT, |
||
| 94 | InputArgument::REQUIRED, |
||
| 95 | 'Character codepoint to search for' |
||
| 96 | ); |
||
| 97 | |||
| 98 | $repositoryNames = $this->getRepositoryNames(); |
||
| 99 | $namesList = implode(', ', $repositoryNames); |
||
| 100 | |||
| 101 | $from = new InputOption( |
||
| 102 | self::OPTION_FROM, |
||
| 103 | null, |
||
| 104 | InputOption::VALUE_OPTIONAL, |
||
| 105 | sprintf('Repository from which the character should be resolved. Choose from: %s', $namesList), |
||
| 106 | array_shift($repositoryNames) |
||
| 107 | ); |
||
| 108 | |||
| 109 | $encoding = new InputOption( |
||
| 110 | self::OPTION_ENCODING, |
||
| 111 | null, |
||
| 112 | InputOption::VALUE_OPTIONAL, |
||
| 113 | 'Encoding of the supplied value. Choose from: dec, hex, utf8', |
||
| 114 | self::ENCODING_HEXADECIMAL |
||
| 115 | ); |
||
| 116 | |||
| 117 | return new InputDefinition([$codepoint, $from, $encoding]); |
||
| 118 | } |
||
| 119 | } |