├── .gitignore ├── composer.json ├── README.md ├── lib ├── Rental.php ├── Movie.php ├── Price.php └── Customer.php ├── tests ├── MovieTest.php └── CustomerTest.php └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | vendor -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "phpunit/phpunit": "3.7.*" 4 | } 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Refactoring - PHP Edition 2 | 3 | This repository contains the same code examples of Martin Fowler's Refactoring book, but written in PHP. 4 | It was used as companion for the talk [Refactoring - Improving the Design of Existing Code](https://speakerdeck.com/mehlah/refactoring-improving-the-design-of-existing-code) 5 | 6 | You can follow the refactoring steps taken, in each branch, starting from [`1-decompose-statement`](https://github.com/craftsmen/refactoring-php-example/tree/1-decompose-statement) 7 | -------------------------------------------------------------------------------- /lib/Rental.php: -------------------------------------------------------------------------------- 1 | _movie = $movie; 11 | $this->_daysRented = $daysRented; 12 | } 13 | 14 | public function getMovie() { 15 | return $this->_movie; 16 | } 17 | 18 | public function getDaysRented() { 19 | return $this->_daysRented; 20 | } 21 | 22 | public function getCharge() { 23 | return $this->_movie->getCharge($this->_daysRented); 24 | } 25 | 26 | public function getFrequentRenterPoints() { 27 | return $this->_movie->getFrequentRenterPoints($this->_daysRented); 28 | } 29 | } 30 | 31 | ?> -------------------------------------------------------------------------------- /lib/Movie.php: -------------------------------------------------------------------------------- 1 | _title = $title; 15 | $this->setpriceCode($priceCode); 16 | } 17 | 18 | public function getPriceCode() { 19 | return $this->_price->getPriceCode(); 20 | } 21 | 22 | public function setPriceCode($arg) { 23 | switch ($arg) { 24 | case self::REGULAR : 25 | $this->_price = new RegularPrice; 26 | break; 27 | case self::CHILDREN : 28 | $this->_price = new ChildrensPrice; 29 | break; 30 | case self::NEW_RELEASE : 31 | $this->_price = new NewReleasePrice; 32 | break; 33 | default : 34 | throw new InvalidArgumentException('Incorrect Price Code'); 35 | } 36 | } 37 | 38 | public function getTitle() { 39 | return $this->_title; 40 | } 41 | 42 | public function getCharge($daysRented) { 43 | return $this->_price->getCharge($daysRented); 44 | } 45 | 46 | public function getFrequentRenterPoints($daysRented) { 47 | return $this->_price->getFrequentRenterPoints($daysRented); 48 | } 49 | } 50 | 51 | ?> -------------------------------------------------------------------------------- /lib/Price.php: -------------------------------------------------------------------------------- 1 | 3) { 22 | $result += ($daysRented - 3) * 1.5; 23 | } 24 | 25 | return $result; 26 | } 27 | } 28 | 29 | class NewReleasePrice extends Price { 30 | public function getPriceCode() { 31 | return Movie::NEW_RELEASE; 32 | } 33 | 34 | public function getCharge($daysRented) { 35 | return $daysRented * 3; 36 | } 37 | 38 | public function getFrequentRenterPoints($daysRented) { 39 | return ($daysRented > 1) ? 2: 1; 40 | } 41 | } 42 | 43 | class RegularPrice extends Price { 44 | public function getPriceCode() { 45 | return Movie::REGULAR; 46 | } 47 | 48 | public function getCharge($daysRented) { 49 | $result = 2; 50 | if ($daysRented > 2) { 51 | $result += ($daysRented - 2) * 1.5; 52 | } 53 | 54 | return $result; 55 | } 56 | } 57 | 58 | ?> -------------------------------------------------------------------------------- /lib/Customer.php: -------------------------------------------------------------------------------- 1 | _name = $name; 12 | } 13 | 14 | public function addRental(Rental $arg) { 15 | $this->_rentals[] = $arg; 16 | } 17 | 18 | public function getName() { 19 | return $this->_name; 20 | } 21 | 22 | public function statement() { 23 | $result = "Rental records for {$this->getName()} \n"; 24 | 25 | foreach ($this->_rentals as $rental) { 26 | // show figures for this rental 27 | $result .= "{$rental->getMovie()->getTitle()} \t {$rental->getCharge()} \n"; 28 | } 29 | 30 | $result .= "Amount owned is {$this->getTotalCharge()} \n"; 31 | $result .= "You earned {$this->getTotalFrequentRenterPoints()} frequent renter points"; 32 | 33 | return $result; 34 | } 35 | 36 | private function getTotalCharge() { 37 | $result = 0; 38 | foreach ($this->_rentals as $rental) { 39 | $result += $rental->getCharge(); 40 | } 41 | return $result; 42 | } 43 | 44 | private function getTotalFrequentRenterPoints() { 45 | $result = 0; 46 | foreach ($this->_rentals as $rental) { 47 | $result += $rental->getFrequentRenterPoints(); 48 | } 49 | return $result; 50 | } 51 | } 52 | 53 | ?> -------------------------------------------------------------------------------- /tests/MovieTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('Star Wars', $sw->getTitle()); 10 | } 11 | 12 | public function testPriceCode() { 13 | $sw = new Movie('Star Wars', Movie::REGULAR); 14 | $this->assertEquals(Movie::REGULAR, $sw->getPriceCode()); 15 | 16 | $toystory = new Movie('Toy Story', Movie::CHILDREN); 17 | $this->assertEquals(Movie::CHILDREN, $toystory->getPriceCode()); 18 | 19 | $skyfall = new Movie('Skyfall', Movie::NEW_RELEASE); 20 | $this->assertEquals(Movie::NEW_RELEASE, $skyfall->getPriceCode()); 21 | } 22 | 23 | public function testInvalidPriceCode() { 24 | $this->setExpectedException('InvalidArgumentException'); 25 | $killbill = new Movie('Kill Bill', 999); 26 | } 27 | 28 | public function testChargeRegular() { 29 | $sw = new Movie('Star Wars', Movie::REGULAR); 30 | $this->assertEquals(2, $sw->getCharge(1)); 31 | $this->assertEquals(3.5, $sw->getCharge(3)); 32 | } 33 | 34 | public function testChargeNewRelease() { 35 | $skyfall = new Movie('Skyfall', Movie::NEW_RELEASE); 36 | $this->assertEquals(6, $skyfall->getCharge(2)); 37 | } 38 | 39 | public function testChargeChildren() { 40 | $toystory = new Movie('Toy Story', Movie::CHILDREN); 41 | $this->assertEquals(1.5, $toystory->getCharge(2)); 42 | $this->assertEquals(1.5, $toystory->getCharge(3)); 43 | $this->assertEquals(3, $toystory->getCharge(4)); 44 | } 45 | } 46 | 47 | ?> -------------------------------------------------------------------------------- /tests/CustomerTest.php: -------------------------------------------------------------------------------- 1 | customer = new Customer('Mehdi'); 9 | } 10 | 11 | public function testName() { 12 | $this->assertEquals('Mehdi', $this->customer->getName()); 13 | } 14 | 15 | public function test_statement_regular_movies() { 16 | $sw = new Movie('Star Wars', 0); 17 | $st = new Movie('Star Trek', 0); 18 | 19 | $rental = new Rental($sw, 3); 20 | $rental2 = new Rental($st, 3); 21 | $this->customer->addRental($rental); 22 | $this->customer->addRental($rental2); 23 | 24 | $result = "Rental records for Mehdi \n"; 25 | $result .= "Star Wars \t 3.5 \n"; 26 | $result .= "Star Trek \t 3.5 \n"; 27 | $result .= "Amount owned is 7 \n"; 28 | $result .= "You earned 2 frequent renter points"; 29 | 30 | $this->assertEquals($result, $this->customer->statement()); 31 | } 32 | 33 | public function test_statement_children_movies() { 34 | $cars = new Movie('Cars', 2); 35 | $toystory = new Movie('Toy Story', 2); 36 | 37 | $rental = new Rental($cars, 1); 38 | $rental2 = new Rental($toystory, 4); 39 | $this->customer->addRental($rental); 40 | $this->customer->addRental($rental2); 41 | 42 | $result = "Rental records for Mehdi \n"; 43 | $result .= "Cars \t 1.5 \n"; 44 | $result .= "Toy Story \t 3 \n"; 45 | $result .= "Amount owned is 4.5 \n"; 46 | $result .= "You earned 2 frequent renter points"; 47 | 48 | $this->assertEquals($result, $this->customer->statement()); 49 | } 50 | 51 | public function test_statement_new_release_movies() { 52 | $skyfall = new Movie('Skyfall', 1); 53 | 54 | $rental = new Rental($skyfall, 1); 55 | $this->customer->addRental($rental); 56 | 57 | $result = "Rental records for Mehdi \n"; 58 | $result .= "Skyfall \t 3 \n"; 59 | $result .= "Amount owned is 3 \n"; 60 | $result .= "You earned 1 frequent renter points"; 61 | 62 | $this->assertEquals($result, $this->customer->statement()); 63 | } 64 | } 65 | 66 | ?> -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "b7c0c969e6d61a7574bd281566bcd977", 3 | "packages": [ 4 | { 5 | "name": "phpunit/php-code-coverage", 6 | "version": "1.2.7", 7 | "source": { 8 | "type": "git", 9 | "url": "git://github.com/sebastianbergmann/php-code-coverage.git", 10 | "reference": "1.2.7" 11 | }, 12 | "dist": { 13 | "type": "zip", 14 | "url": "https://github.com/sebastianbergmann/php-code-coverage/archive/1.2.7.zip", 15 | "reference": "1.2.7", 16 | "shasum": "" 17 | }, 18 | "require": { 19 | "php": ">=5.3.3", 20 | "phpunit/php-file-iterator": ">=1.3.0@stable", 21 | "phpunit/php-token-stream": ">=1.1.3@stable", 22 | "phpunit/php-text-template": ">=1.1.1@stable" 23 | }, 24 | "suggest": { 25 | "ext-dom": "*", 26 | "ext-xdebug": ">=2.0.5" 27 | }, 28 | "time": "2012-12-02 14:54:55", 29 | "type": "library", 30 | "installation-source": "dist", 31 | "autoload": { 32 | "classmap": [ 33 | "PHP/" 34 | ] 35 | }, 36 | "notification-url": "https://packagist.org/downloads/", 37 | "include-path": [ 38 | "" 39 | ], 40 | "license": [ 41 | "BSD-3-Clause" 42 | ], 43 | "authors": [ 44 | { 45 | "name": "Sebastian Bergmann", 46 | "email": "sb@sebastian-bergmann.de", 47 | "role": "lead" 48 | } 49 | ], 50 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 51 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 52 | "keywords": [ 53 | "testing", 54 | "coverage", 55 | "xunit" 56 | ] 57 | }, 58 | { 59 | "name": "phpunit/php-file-iterator", 60 | "version": "1.3.3", 61 | "source": { 62 | "type": "git", 63 | "url": "git://github.com/sebastianbergmann/php-file-iterator.git", 64 | "reference": "1.3.3" 65 | }, 66 | "dist": { 67 | "type": "zip", 68 | "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", 69 | "reference": "1.3.3", 70 | "shasum": "" 71 | }, 72 | "require": { 73 | "php": ">=5.3.3" 74 | }, 75 | "time": "2012-10-11 04:44:38", 76 | "type": "library", 77 | "installation-source": "dist", 78 | "autoload": { 79 | "classmap": [ 80 | "File/" 81 | ] 82 | }, 83 | "notification-url": "https://packagist.org/downloads/", 84 | "include-path": [ 85 | "" 86 | ], 87 | "license": [ 88 | "BSD-3-Clause" 89 | ], 90 | "authors": [ 91 | { 92 | "name": "Sebastian Bergmann", 93 | "email": "sb@sebastian-bergmann.de", 94 | "role": "lead" 95 | } 96 | ], 97 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 98 | "homepage": "http://www.phpunit.de/", 99 | "keywords": [ 100 | "filesystem", 101 | "iterator" 102 | ] 103 | }, 104 | { 105 | "name": "phpunit/php-text-template", 106 | "version": "1.1.4", 107 | "source": { 108 | "type": "git", 109 | "url": "git://github.com/sebastianbergmann/php-text-template.git", 110 | "reference": "1.1.4" 111 | }, 112 | "dist": { 113 | "type": "zip", 114 | "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", 115 | "reference": "1.1.4", 116 | "shasum": "" 117 | }, 118 | "require": { 119 | "php": ">=5.3.3" 120 | }, 121 | "time": "2012-10-31 11:15:28", 122 | "type": "library", 123 | "installation-source": "dist", 124 | "autoload": { 125 | "classmap": [ 126 | "Text/" 127 | ] 128 | }, 129 | "notification-url": "https://packagist.org/downloads/", 130 | "include-path": [ 131 | "" 132 | ], 133 | "license": [ 134 | "BSD-3-Clause" 135 | ], 136 | "authors": [ 137 | { 138 | "name": "Sebastian Bergmann", 139 | "email": "sb@sebastian-bergmann.de", 140 | "role": "lead" 141 | } 142 | ], 143 | "description": "Simple template engine.", 144 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 145 | "keywords": [ 146 | "template" 147 | ] 148 | }, 149 | { 150 | "name": "phpunit/php-timer", 151 | "version": "1.0.4", 152 | "source": { 153 | "type": "git", 154 | "url": "git://github.com/sebastianbergmann/php-timer.git", 155 | "reference": "1.0.4" 156 | }, 157 | "dist": { 158 | "type": "zip", 159 | "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", 160 | "reference": "1.0.4", 161 | "shasum": "" 162 | }, 163 | "require": { 164 | "php": ">=5.3.3" 165 | }, 166 | "time": "2012-10-11 04:45:58", 167 | "type": "library", 168 | "installation-source": "dist", 169 | "autoload": { 170 | "classmap": [ 171 | "PHP/" 172 | ] 173 | }, 174 | "notification-url": "https://packagist.org/downloads/", 175 | "include-path": [ 176 | "" 177 | ], 178 | "license": [ 179 | "BSD-3-Clause" 180 | ], 181 | "authors": [ 182 | { 183 | "name": "Sebastian Bergmann", 184 | "email": "sb@sebastian-bergmann.de", 185 | "role": "lead" 186 | } 187 | ], 188 | "description": "Utility class for timing", 189 | "homepage": "http://www.phpunit.de/", 190 | "keywords": [ 191 | "timer" 192 | ] 193 | }, 194 | { 195 | "name": "phpunit/php-token-stream", 196 | "version": "1.1.5", 197 | "source": { 198 | "type": "git", 199 | "url": "git://github.com/sebastianbergmann/php-token-stream.git", 200 | "reference": "1.1.5" 201 | }, 202 | "dist": { 203 | "type": "zip", 204 | "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", 205 | "reference": "1.1.5", 206 | "shasum": "" 207 | }, 208 | "require": { 209 | "ext-tokenizer": "*", 210 | "php": ">=5.3.3" 211 | }, 212 | "time": "2012-10-11 04:47:14", 213 | "type": "library", 214 | "installation-source": "dist", 215 | "autoload": { 216 | "classmap": [ 217 | "PHP/" 218 | ] 219 | }, 220 | "notification-url": "https://packagist.org/downloads/", 221 | "include-path": [ 222 | "" 223 | ], 224 | "license": [ 225 | "BSD-3-Clause" 226 | ], 227 | "authors": [ 228 | { 229 | "name": "Sebastian Bergmann", 230 | "email": "sb@sebastian-bergmann.de", 231 | "role": "lead" 232 | } 233 | ], 234 | "description": "Wrapper around PHP's tokenizer extension.", 235 | "homepage": "http://www.phpunit.de/", 236 | "keywords": [ 237 | "tokenizer" 238 | ] 239 | }, 240 | { 241 | "name": "phpunit/phpunit", 242 | "version": "3.7.10", 243 | "source": { 244 | "type": "git", 245 | "url": "git://github.com/sebastianbergmann/phpunit.git", 246 | "reference": "3.7.10" 247 | }, 248 | "dist": { 249 | "type": "zip", 250 | "url": "https://github.com/sebastianbergmann/phpunit/archive/3.7.10.zip", 251 | "reference": "3.7.10", 252 | "shasum": "" 253 | }, 254 | "require": { 255 | "php": ">=5.3.3", 256 | "phpunit/php-file-iterator": ">=1.3.1", 257 | "phpunit/php-text-template": ">=1.1.1", 258 | "phpunit/php-code-coverage": ">=1.2.1", 259 | "phpunit/php-timer": ">=1.0.2", 260 | "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", 261 | "symfony/yaml": ">=2.1.0", 262 | "ext-dom": "*", 263 | "ext-pcre": "*", 264 | "ext-reflection": "*", 265 | "ext-spl": "*" 266 | }, 267 | "suggest": { 268 | "phpunit/php-invoker": ">=1.1.0", 269 | "ext-json": "*", 270 | "ext-simplexml": "*", 271 | "ext-tokenizer": "*" 272 | }, 273 | "time": "2012-12-02 14:56:55", 274 | "bin": [ 275 | "composer/bin/phpunit" 276 | ], 277 | "type": "library", 278 | "extra": { 279 | "branch-alias": { 280 | "dev-master": "3.7.x-dev" 281 | } 282 | }, 283 | "installation-source": "dist", 284 | "autoload": { 285 | "classmap": [ 286 | "PHPUnit/" 287 | ] 288 | }, 289 | "notification-url": "https://packagist.org/downloads/", 290 | "include-path": [ 291 | "", 292 | "../../symfony/yaml/" 293 | ], 294 | "license": [ 295 | "BSD-3-Clause" 296 | ], 297 | "authors": [ 298 | { 299 | "name": "Sebastian Bergmann", 300 | "email": "sebastian@phpunit.de", 301 | "role": "lead" 302 | } 303 | ], 304 | "description": "The PHP Unit Testing framework.", 305 | "homepage": "http://www.phpunit.de/", 306 | "keywords": [ 307 | "testing", 308 | "phpunit", 309 | "xunit" 310 | ] 311 | }, 312 | { 313 | "name": "phpunit/phpunit-mock-objects", 314 | "version": "1.2.2", 315 | "source": { 316 | "type": "git", 317 | "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", 318 | "reference": "1.2.2" 319 | }, 320 | "dist": { 321 | "type": "zip", 322 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.2.zip", 323 | "reference": "1.2.2", 324 | "shasum": "" 325 | }, 326 | "require": { 327 | "php": ">=5.3.3", 328 | "phpunit/php-text-template": ">=1.1.1@stable" 329 | }, 330 | "suggest": { 331 | "ext-soap": "*" 332 | }, 333 | "time": "2012-11-05 10:39:13", 334 | "type": "library", 335 | "installation-source": "dist", 336 | "autoload": { 337 | "classmap": [ 338 | "PHPUnit/" 339 | ] 340 | }, 341 | "notification-url": "https://packagist.org/downloads/", 342 | "include-path": [ 343 | "" 344 | ], 345 | "license": [ 346 | "BSD-3-Clause" 347 | ], 348 | "authors": [ 349 | { 350 | "name": "Sebastian Bergmann", 351 | "email": "sb@sebastian-bergmann.de", 352 | "role": "lead" 353 | } 354 | ], 355 | "description": "Mock Object library for PHPUnit", 356 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 357 | "keywords": [ 358 | "mock", 359 | "xunit" 360 | ] 361 | }, 362 | { 363 | "name": "symfony/yaml", 364 | "version": "v2.1.6", 365 | "target-dir": "Symfony/Component/Yaml", 366 | "source": { 367 | "type": "git", 368 | "url": "https://github.com/symfony/Yaml", 369 | "reference": "v2.1.6" 370 | }, 371 | "dist": { 372 | "type": "zip", 373 | "url": "https://github.com/symfony/Yaml/archive/v2.1.6.zip", 374 | "reference": "v2.1.6", 375 | "shasum": "" 376 | }, 377 | "require": { 378 | "php": ">=5.3.3" 379 | }, 380 | "time": "2012-12-06 10:00:55", 381 | "type": "library", 382 | "installation-source": "dist", 383 | "autoload": { 384 | "psr-0": { 385 | "Symfony\\Component\\Yaml": "" 386 | } 387 | }, 388 | "notification-url": "https://packagist.org/downloads/", 389 | "license": [ 390 | "MIT" 391 | ], 392 | "authors": [ 393 | { 394 | "name": "Fabien Potencier", 395 | "email": "fabien@symfony.com" 396 | }, 397 | { 398 | "name": "Symfony Community", 399 | "homepage": "http://symfony.com/contributors" 400 | } 401 | ], 402 | "description": "Symfony Yaml Component", 403 | "homepage": "http://symfony.com" 404 | } 405 | ], 406 | "packages-dev": null, 407 | "aliases": [ 408 | 409 | ], 410 | "minimum-stability": "stable", 411 | "stability-flags": [ 412 | 413 | ] 414 | } 415 | --------------------------------------------------------------------------------