├── .gitignore ├── public └── index.php ├── src └── App.php ├── phpspec.yml ├── todo.md ├── composer.json ├── Make.config ├── Makefile └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp-dev 2 | /vendor 3 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | run(); 7 | -------------------------------------------------------------------------------- /src/App.php: -------------------------------------------------------------------------------- 1 | run linter and tests (default target)" 20 | @echo " phplint > run php linter (php -l)" 21 | @echo " phpspec > run phpspec" 22 | @echo "" 23 | @echo " setup > install composer dependencies" 24 | @echo " deps_update > explicitly update dependencies (composer update)" 25 | @echo " clean > stop server, clean tmp files and vendor dir" 26 | @echo " clean_tmp > clean temporary files (and stop server)" 27 | @echo " clean_vendor > remove vendor dir" 28 | @echo "" 29 | @echo " server_start > start dev server" 30 | @echo " server_stop > stop dev server" 31 | 32 | .PHONY: clean 33 | clean: clean_tmp clean_vendor 34 | 35 | .PHONY: clean_tmp 36 | clean_tmp: server_stop 37 | test ! -e "$(TMP_DIR)" || rm -r "$(TMP_DIR)" 38 | 39 | .PHONY: clean_vendor 40 | clean_vendor: 41 | test ! -e vendor || rm -r vendor 42 | 43 | .PHONY: setup 44 | setup: vendor/autoload.php 45 | 46 | # task to explicitly update the dependencies 47 | .PHONY: deps_update 48 | deps_update: 49 | $(COMPOSER_BIN) update 50 | 51 | # runs only if a source file has been modified 52 | .PHONY: phpspec 53 | phpspec: $(TMP_DIR)/phpspec 54 | 55 | $(TMP_DIR)/phpspec: $(TMP_DIR) vendor/autoload.php phpspec.yml $(src) 56 | $(PHP_BIN) ./vendor/bin/phpspec run 57 | touch $@ 58 | 59 | # lint all modified sources 60 | .PHONY: phplint 61 | phplint: $(TMP_DIR)/phplint 62 | 63 | $(TMP_DIR)/phplint: $(TMP_DIR) $(src) 64 | @echo lint source files... 65 | @$(foreach f,$(filter-out $(TMP_DIR),$?),$(PHP_BIN) -l $(f);) 66 | touch $@ 67 | 68 | # we only do `install`, as composer.json may change 69 | # without wanting to update dependencies. 70 | # Please check the composer warning of out-of-sync 71 | # packages. 72 | composer.lock: composer.json 73 | $(COMPOSER_BIN) install 74 | touch $@ 75 | 76 | # make sure deps get installed even if 77 | # composer.lock exists initially (or 78 | # after `git pull`) 79 | vendor/autoload.php: composer.lock 80 | $(COMPOSER_BIN) install 81 | touch $@ 82 | 83 | .PHONY: server_start 84 | server_start: $(TMP_DIR)/server.PID 85 | 86 | .PHONY: server_stop 87 | server_stop: 88 | test ! -e $(TMP_DIR)/server.PID || { kill `cat $(TMP_DIR)/server.PID`; rm $(TMP_DIR)/server.PID; } 89 | 90 | # starts the server, redirect stdout/stderr to log files in TMP_DIR, 91 | # and writes the process id to the target file 92 | # Note: If TMP_DIR does not yet exist, we create it manually instead 93 | # of declaring a dependency of it. The reason is that we don't want 94 | # to run this rule if the server is already started, but the TMP_DIR's 95 | # timestamp has been modified 96 | $(TMP_DIR)/server.PID: 97 | mkdir -p $(TMP_DIR) 98 | $(PHP_BIN) -S $(DEV_SERVER_ADDR) -t $(PUBLIC_DIR) >$(TMP_DIR)/server.log 2>$(TMP_DIR)/server.err.log & echo $$! > $@; 99 | 100 | $(TMP_DIR): 101 | mkdir -p $@ 102 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | PHP Project set-up using GNU make Makefile 2 | ========================================= 3 | 4 | This aims to be a starting point for your 5 | new PHP project. It defines tasks which 6 | are common to most of the PHP projects 7 | as Makefile targets. 8 | 9 | Usage 10 | -------- 11 | 12 | 1. clone this repository 13 | 2. run `make` (this will install dependencies and run the linter and tests). 14 | 3. run `make list` to see other targets. 15 | 16 | After that, you may want to have a look at the Makefile itself, 17 | and adopt it to your project. 18 | 19 | About build tools and task runners 20 | ---------------------------------- 21 | 22 | As PHP is a dynamic language without 23 | compilation, there was not much need 24 | for a tool like [Make](https://www.gnu.org/software/make/). 25 | Since some years though, the set-ups 26 | even for PHP projects have become more 27 | complex. As a result, there are many 28 | *Task runners* available. In PHP, a 29 | good one of those is [robo.li](http://robo.li/). 30 | 31 | What they (normally) don't provide, is the 32 | declaration of dependencies, which allow 33 | to run an *incremental build* (where the "build" 34 | could actually be any kind of task). 35 | If the build tool knows this dependencies, it 36 | can skip commands which would produce the 37 | same output as before, because the sources 38 | are the same. This is a very important 39 | feature of more traditional build tools like 40 | *Make*. 41 | 42 | Why Make (and not phing, ant, ...) 43 | ---------------------------------- 44 | 45 | First of all, as described above, I want a tool which 46 | knows the dependency graph of my application. Depending 47 | on the application, it could make sense to use a 48 | task runner (*robo.li*, or one of the JavaScript task 49 | runners, which provide very useful tools for frontend 50 | development) *in addition* to a "real" build tool. 51 | 52 | I don't like the xml declaration style used by 53 | build tools like *ant* or *phing*. In my opinion, 54 | the syntax of a Makefile is much more readable and 55 | concise (once you got used to the few 56 | [automatic variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html)). 57 | 58 | Another reason is that you can define commands which are 59 | directly executed in a shell. For common tasks, such as 60 | file-system operations, this is much easier and faster 61 | than using PHP. The downside of course is, that it 62 | doesn't work on every platform (if you don't be very 63 | careful which commands you use). 64 | 65 | Features 66 | ---------- 67 | 68 | The Makefile target which are intended to be used from the 69 | command line, are listed by `make list`: 70 | 71 | ```sh 72 | $ make list 73 | 74 | Useful targets: 75 | 76 | test > run linter and tests (default target) 77 | phplint > run php linter (php -l) 78 | phpspec > run phpspec 79 | 80 | setup > install composer dependencies 81 | deps_update > explicitly update dependencies (composer update) 82 | clean > stop server, clean tmp files and vendor dir 83 | clean_tmp > clean temporary files (and stop server) 84 | clean_vendor > remove vendor dir 85 | 86 | server_start > start dev server 87 | server_stop > stop dev server 88 | ``` 89 | 90 | The dependencies of each target (*prerequisites* in make terminology) 91 | are declared very carefully, so that you can run `make test` and 92 | only the out-of-date targets are updated. Examples: 93 | 94 | * You can directly start with `make test` (or just `make`, as `test` 95 | is the default target). It sees that the composer dependencies 96 | are not yet installed, and runs `composer install`. 97 | * `make test` does not do anything, if you have not updated any 98 | source files. 99 | * `make phplint` only lints the modified source files. 100 | 101 | There are a few PHP 102 | files included, but only as an example project. The idea 103 | is to *not* limit you on your choices regarding frameworks, 104 | project structure, and so on. The only choice which is done, 105 | is the testing tool, which is *phpspec*. This allows 106 | to show a useful implementation of a `test` target. 107 | It should be very easy to use *phpunit* instead: just 108 | change the dependency in the composer.json and modify 109 | the phpspec target to call phpunit instead. 110 | 111 | --------------------------------------------------------------------------------