├── .devcontainer ├── .gitignore ├── .npmrc ├── composer.config.json ├── devcontainer.json ├── docker-php.ini └── php-cli.ini ├── .dockerignore ├── .doctum.php ├── .drone.yml ├── .editorconfig ├── .env.example ├── .gitattributes.example ├── .github ├── CODEOWNERS.md ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ ├── Custom.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── SUPPORT.md └── workflows │ └── ci.yml ├── .gitignore ├── .pcit.php ├── .pcit.yml ├── .php-cs-fixer.php ├── .styleci.yml ├── .vscode └── settings.json ├── CHANGELOG.example.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.example.md ├── README.md ├── composer.demo.json ├── composer.json ├── config └── config-file.php ├── deploy ├── docker-stack.yml └── test.Dockerfile ├── docker-compose.yml ├── docker-workspace.yml ├── phpunit.xml ├── public ├── .gitignore ├── .user.ini ├── demo.html └── index.php ├── renovate.json ├── src └── Example │ ├── Console │ └── ExampleCommand.php │ ├── Example.php │ ├── Exception │ └── ExampleException.php │ ├── Providers │ ├── BBBProvider.php │ └── CacheProvider.php │ ├── Service │ ├── AAA.php │ └── BBB.php │ └── Support │ ├── Config.php │ ├── Facade.php │ └── ServiceProvider.php └── tests ├── .gitignore └── Example ├── ExampleTest.php └── ExampleTestCase.php /.devcontainer/.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !.gitignore 3 | !devcontainer.json 4 | !docker-php.ini 5 | !php-cli.ini 6 | !.npmrc 7 | !composer.config.json 8 | -------------------------------------------------------------------------------- /.devcontainer/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmmirror.com 2 | prefix=/tmp/node/npm 3 | cache=/tmp/node/.npm 4 | -------------------------------------------------------------------------------- /.devcontainer/composer.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": {}, 3 | "repositories": { 4 | "packagist": { 5 | "type": "composer", 6 | "url": "https://mirrors.aliyun.com/composer/" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference 3 | // fix me 4 | "name": "php-demo", 5 | 6 | // The order of the files is important since later files override previous ones 7 | "dockerComposeFile": [ 8 | "../docker-workspace.yml" 9 | ], 10 | 11 | // fix me 12 | "service": "workspace", 13 | "runServices": [ 14 | "workspace" 15 | ], 16 | // fix me 与 docker-workspace.yml 中的路径一致 17 | "workspaceFolder": "/app/demo", 18 | "shutdownAction": "stopCompose", // none stopCompose 19 | 20 | // [Optional] If you are using SSH keys w/Git, copy them and set correct permissions 21 | // "postCreateCommand": "mkdir -p ~/.ssh && cp -r ~/.ssh-localhost/* ~/.ssh && chmod 700 ~/.ssh && chmod 600 ~/.ssh/*" 22 | "extensions": [ 23 | "xdebug.php-debug", 24 | "editorconfig.editorconfig" 25 | ], 26 | "settings": { 27 | // If you are using an Alpine-based image, change this to /bin/ash 28 | // "terminal.integrated.shell.linux": "/bin/bash" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.devcontainer/docker-php.ini: -------------------------------------------------------------------------------- 1 | ; 2 | ; http://www.jinbuguo.com/php/php.ini.html 3 | ; 4 | 5 | error_log= /var/log/php/error.log 6 | 7 | ; 你可以在这里自定义 php 配置 8 | 9 | ; extension=tideways_xhprof.so 10 | 11 | ; opcache 12 | ; https://laravel-news.com/php-opcache-docker 13 | 14 | [opcache] 15 | opcache.enable=false 16 | ; 0 means it will check on every request 17 | ; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production 18 | opcache.revalidate_freq=0 19 | opcache.validate_timestamps=1 20 | opcache.max_accelerated_files=10000 21 | opcache.memory_consumption=192 22 | opcache.max_wasted_percentage=10 23 | opcache.interned_strings_buffer=16 24 | opcache.fast_shutdown=1 25 | 26 | ; JIT 27 | ; https://wiki.php.net/rfc/jit 28 | ; opcache.jit_buffer_size=1024K 29 | ; opcache.jit=1205 30 | ; 1235 31 | ; opcache.jit_debug=0 32 | ; opcache.preload=/app/symfony4.4/var/cache/development/srcApp_KernelDevelopmentDebugContainer.preload.php 33 | ; opcache.preload_user=www-data 34 | 35 | [xdebug] 36 | ; https://xdebug.org/docs/all_settings 37 | ; 是否启用 Xdebug 扩展,若启用取消注释即可,请仅在开发环境启用 38 | zend_extension=xdebug 39 | -------------------------------------------------------------------------------- /.devcontainer/php-cli.ini: -------------------------------------------------------------------------------- 1 | memory_limit=-1 2 | ; date.timezone= 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | 3 | .idea 4 | 5 | vendor 6 | 7 | node_modules/ 8 | 9 | public/js/ 10 | public/css/ 11 | mix-manifest.json 12 | 13 | yarn-error.log 14 | -------------------------------------------------------------------------------- /.doctum.php: -------------------------------------------------------------------------------- 1 | files() 18 | ->name('*.php') 19 | // ->exclude('tests') 20 | ->in($dir = __DIR__.'/src'); 21 | 22 | // $versions = GitVersionCollection::create($dir) 23 | // ->addFromTags('18.*.*')// add tag 24 | // ->add('master', 'master branch'); // add branch 25 | 26 | return new Doctum($iterator); 27 | 28 | // return new Doctum($iterator, [ 29 | // 'theme' => 'symfony', 30 | // 'versions' => $versions, 31 | // 'title' => 'Title API', 32 | // 'build_dir' => __DIR__.'/build/%version%', 33 | // 'cache_dir' => __DIR__.'/cache/%version%', 34 | // 'remote_repository' => new GitHubRemoteRepository('username/repo', __DIR__), 35 | // 'default_opened_level' => 2, 36 | // ] 37 | // ); 38 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | # @link https://docs.drone.io/ 2 | # @link https://github.com/khs1994-docker/ci 3 | # 4 | # 项目构建设置中 Repository Hooks 全部勾选 5 | # 6 | 7 | # https://docs.drone.io/secret/encrypted/ 8 | # kind: secret 9 | # name: username 10 | # data: hl3v+FODjduX0UpXBHgYzPzVTppQblg51CVgCbgDk4U= 11 | 12 | --- 13 | 14 | kind: pipeline 15 | name: default 16 | 17 | # type: kubernetes 18 | type: docker 19 | 20 | # workspace: 21 | # base: /app 22 | # path: ./ 23 | 24 | platform: 25 | os: linux 26 | arch: amd64 27 | # arm64 28 | 29 | clone: 30 | depth: 50 31 | # disable: true 32 | 33 | steps: 34 | # install dep 35 | - name: install 36 | # image: composer:2.8.3 37 | image: khs1994/php:8.3.12-composer-alpine 38 | commands: 39 | - pwd 40 | - composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ 41 | - composer install -q --ignore-platform-reqs 42 | # - composer update -q --ignore-platform-reqs 43 | volumes: 44 | - name: cache 45 | path: /tmp 46 | 47 | # test script 48 | - name: script 49 | image: khs1994/php:8.3.12-fpm-alpine 50 | # pull: always | never | if-not-exists 51 | # detach: true 52 | # privileged: true 53 | # network_mode: host 54 | # user: www-data 55 | # depends_on: 56 | # - "" 57 | commands: 58 | - pwd 59 | - mv $${PHP_INI_DIR}/conf.d/docker-php-ext-xdebug.ini.default $${PHP_INI_DIR}/conf.d/docker-php-ext-xdebug.ini 60 | # 服务初始化需要时间,这里延迟执行 61 | - sleep 20 62 | - vendor/bin/phpunit --coverage-clover=coverage.xml 63 | # volumes: 64 | # - /Users/khs1994/khs1994/khs1994-lnmp/tmp/cache:/tmp/cache 65 | # - /data/lnmp/tmp/cache:/tmp/cache 66 | when: 67 | # target: 68 | # - production 69 | # status: 70 | # - failure 71 | # - success 72 | # event: 73 | # - tag 74 | # event: [push, tag] 75 | # event: [push, pull_request, tag] 76 | event: [push, pull_request, tag] 77 | # branch: 78 | # - master 79 | # branch: 80 | # - prefix/* 81 | # branch: [master, develop] 82 | # branch: 83 | # include: [ master, release/* ] 84 | # exclude: [ release/1.0.0, release/1.1.* ] 85 | # repo: 86 | # - octocat/hello-world 87 | 88 | # when tag push, build docker image 89 | # http://plugins.drone.io/drone-plugins/drone-docker/ 90 | - name: publish_php 91 | image: plugins/docker 92 | settings: 93 | # registry: docker.khs1994.com 94 | repo: khs1994/php 95 | tags: 8.3.12-pro-${DRONE_TAG}-alpine 96 | target: php 97 | mirror: https://hub-mirror.c.163.com 98 | # build_args: 99 | # - key=value 100 | # dockerfile: Dockerfile 101 | # dockerfile: path/to/Dockerfile 102 | debug: "true" 103 | launch_debug: "true" 104 | username: 105 | from_secret: docker_username 106 | password: 107 | from_secret: docker_password 108 | when: 109 | # 110 | # 首先在命令行设置好相关变量 DRONE_SERVER DRONE_TOKEN 右上角 Token 有详细的说明 111 | # 112 | # 手动在命令行执行以下命令才会执行此步 113 | # 114 | # $ drone deploy khs1994-php/example 6 staging 115 | # 116 | event: [ tag ] 117 | 118 | - name: publish_nginx 119 | image: plugins/docker 120 | settings: 121 | repo: khs1994/nginx 122 | tags: 1.17.0-pro-${DRONE_TAG}-alpine 123 | target: nginx 124 | mirror: https://hub-mirror.c.163.com 125 | username: 126 | from_secret: docker_username 127 | password: 128 | from_secret: docker_password 129 | when: 130 | # 131 | # 手动在命令行执行以下命令才会执行此步 132 | # 133 | # $ drone deploy khs1994-php/example 6 staging 134 | # 135 | # 136 | event: [ tag ] 137 | 138 | # 139 | # CI/CD 构建生产环境 PHP NGINX 镜像 140 | # 141 | - name: publish_php_to_prod 142 | image: plugins/docker 143 | settings: 144 | repo: khs1994/php 145 | tags: 8.3.12-pro-${DRONE_TAG}-alpine 146 | target: php 147 | mirror: https://hub-mirror.c.163.com 148 | username: 149 | from_secret: docker_username 150 | password: 151 | from_secret: docker_password 152 | when: 153 | # 154 | # 手动在命令行执行以下命令才会执行此步 155 | # 156 | # $ drone deploy khs1994-php/demo 6 production 157 | # 158 | event: [ tag ] 159 | 160 | - name: publish_nginx_to_prod 161 | image: plugins/docker 162 | settings: 163 | # registry: docker.khs1994.com 164 | repo: khs1994/nginx 165 | tags: 1.17.0-pro-${DRONE_TAG}-alpine 166 | target: nginx 167 | mirror: https://hub-mirror.c.163.com 168 | username: 169 | from_secret: docker_username 170 | password: 171 | from_secret: docker_password 172 | when: 173 | # 174 | # 手动在命令行执行以下命令才会执行此步 175 | # 176 | # $ drone deploy khs1994-php/demo 6 production 177 | # 178 | # 179 | event: [ tag ] 180 | 181 | - name: after_success 182 | image: khs1994/php:8.3.12-composer-alpine 183 | when: 184 | status: success 185 | commands: 186 | - bash <(curl -s https://codecov.io/bash) 187 | environment: 188 | CODECOV_TOKEN: 189 | from_secret: codecov_token 190 | 191 | - name: after_failure 192 | image: bash 193 | failure: ignore 194 | when: 195 | status: 196 | - failure 197 | commands: 198 | - echo "build failure" 199 | 200 | services: 201 | - name: mysql 202 | image: mysql:5.7.22 203 | environment: 204 | MYSQL_DATABASE: test 205 | MYSQL_ROOT_PASSWORD: mytest 206 | # entrypoint: [ "mysqld" ] 207 | command: [ "--character-set-server=utf8mb4", "--default-authentication-plugin=mysql_native_password" ] 208 | 209 | # - name: postgresql 210 | # image: postgres:12.0-alpine 211 | # environment: 212 | # - POSTGRES_USER=postgres 213 | # - POSTGRES_DB=test 214 | 215 | - name: redis 216 | image: redis:7.0.0-alpine 217 | 218 | # - name: mongodb 219 | # image: mongo:4.1.0 220 | # command: [ --smallfiles ] 221 | 222 | volumes: 223 | - name: cache 224 | host: 225 | path: /tmp 226 | 227 | # matrix: 228 | # COMPOSER_VERSION: 229 | # - 2.8.3 230 | # PHP_VERSION: 231 | # - 8.3.12 232 | # - 8.1.31 233 | # - 8.0.30 234 | # # - 7.4.33 235 | # # - 7.3.33 236 | # # - 7.2.34 237 | # # - 7.1.33 238 | # # - 7.0.33 239 | # # - 5.6.40 240 | # NGINX_VERSION: 241 | # - 1.17.0 242 | # REDIS_VERSION: 243 | # - 7.0.0 244 | # MYSQL_VERSION: 245 | # # - 8.0.33 246 | # - 5.7.22 247 | # MONGODB_VERSION: 248 | # - 4.1.0 249 | # POSTGRESQL_VERSION: 250 | # - 12.0-alpine 251 | 252 | # matrix: 253 | # include: 254 | # - PHP_VERSION=7.2.34 255 | # REDIS_VERSION=7.0.0 256 | # - PHP_VERSION=7.1.33 257 | # REDIS_VERSION=7.0.0 258 | 259 | # trigger: 260 | # branch: 261 | # - master 262 | # include: [ master, dev, feature/* ] 263 | # exclude: [ release/1.0.0, release/1.1.* ] 264 | # event: 265 | # - cron 266 | # - custom 267 | # - promote 268 | # - pull_request 269 | # - push 270 | # - rollback 271 | # - tag 272 | # exclude: 273 | # - pull_request 274 | # ref: 275 | # - refs/heads/feature-* 276 | # - refs/tags/v1.* 277 | 278 | # --- 279 | 280 | # kind: pipeline 281 | # type: docker 282 | # name: ci 283 | 284 | # depends_on: 285 | # - "default" 286 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | 7 | indent_style = space 8 | 9 | indent_size = 2 10 | 11 | charset = utf-8 12 | 13 | trim_trailing_whitespace = true 14 | 15 | insert_final_newline = true 16 | 17 | end_of_line = lf 18 | 19 | [*.md] 20 | 21 | trim_trailing_whitespace = true 22 | 23 | [*.py] 24 | 25 | indent_size = 4 26 | 27 | [*.php] 28 | 29 | indent_size = 4 30 | 31 | [*.{go,java}] 32 | 33 | indent_size = 4 34 | 35 | [*.xml] 36 | 37 | indent_size = 4 38 | 39 | [Makefile] 40 | 41 | indent_style = tab 42 | 43 | [{package.json,.travis.yml,.pcit.yml,.drone.yml}] 44 | 45 | indent_size = 2 46 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DOCKER_HUB_USERNAME=khs1994 2 | 3 | PHP_VERSION=8.3.12 4 | # PHP_VERSION=8.1.31 5 | # PHP_VERSION=8.0.30 6 | # PHP_VERSION=7.4.33 7 | # PHP_VERSION=7.3.33 8 | # PHP_VERSION=7.2.34 9 | # PHP_VERSION=7.1.33 10 | # PHP_VERSION=7.0.33 11 | # PHP_VERSION=5.6.40 12 | 13 | NODE_VERSION=20.5.1 14 | -------------------------------------------------------------------------------- /.gitattributes.example: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | /.github export-ignore 4 | /docs export-ignore 5 | /examples export-ignore 6 | /tests export-ignore 7 | /.dockerignore export-ignore 8 | /.drone.yml export-ignore 9 | /.editorconfig export-ignore 10 | /.gitattributes export-ignore 11 | /.gitignore export-ignore 12 | /.gitmodules export-ignore 13 | /.php_cs export-ignore 14 | /.doctum.php export-ignore 15 | /.styleci.yml export-ignore 16 | /CHANGELOG.md export-ignore 17 | /CONTRIBUTING.md export-ignore 18 | .scrutinizer.yml export-ignore 19 | /docker-compose.yml export-ignore 20 | /docker-stack.yml export-ignore 21 | /Dockerfile export-ignore 22 | /phpunit.xml export-ignore 23 | /renovate.json export-ignore 24 | /test.Dockerfile export-ignore 25 | 26 | # merge skip file 27 | # $ git config --global merge.ours.driver true 28 | # # $ git merge -s ours 29 | # 30 | # @see https://stackoverflow.com/questions/15232000/git-ignore-files-during-merge 31 | # @see https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#_merge_strategies 32 | 33 | # CHANGELOG.md merge=ours 34 | # composer.json merge=ours 35 | # docker-compose.yml merge=ours 36 | # Dockerfile merge=ours 37 | -------------------------------------------------------------------------------- /.github/CODEOWNERS.md: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 2 | # This is a comment. 3 | # Each line is a file pattern followed by one or more owners. 4 | 5 | # These owners will be the default owners for everything in 6 | # the repo. Unless a later match takes precedence, 7 | # @global-owner1 and @global-owner2 will be requested for 8 | # review when someone opens a pull request. 9 | * @global-owner1 @global-owner2 10 | 11 | # Order is important; the last matching pattern takes the most 12 | # precedence. When someone opens a pull request that only 13 | # modifies JS files, only @js-owner and not the global 14 | # owner(s) will be requested for a review. 15 | *.js @js-owner 16 | 17 | # You can also use email addresses if you prefer. They'll be 18 | # used to look up users just like we do for commit author 19 | # emails. 20 | *.go docs@example.com 21 | 22 | # In this example, @doctocat owns any files in the build/logs 23 | # directory at the root of the repository and any of its 24 | # subdirectories. 25 | /build/logs/ @doctocat 26 | 27 | # The `docs/*` pattern will match files like 28 | # `docs/getting-started.md` but not further nested files like 29 | # `docs/build-app/troubleshooting.md`. 30 | docs/* docs@example.com 31 | 32 | # In this example, @octocat owns any file in an apps directory 33 | # anywhere in your repository. 34 | apps/ @octocat 35 | 36 | # In this example, @doctocat owns any file in the `/docs` 37 | # directory in the root of your repository. 38 | /docs/ @doctocat 39 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at khs1994@khs1994.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://www.contributor-covenant.org/version/1/4/][version] 44 | 45 | [homepage]: https://www.contributor-covenant.org 46 | [version]: https://www.contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | 8 | 9 | ### 操作系统 10 | 11 | 12 | 13 | * [x] Windows 10 14 | * [x] Linux 15 | * [x] Ubuntu 16 | * [x] Debian 17 | * [x] CentOS 18 | * [x] CoreOS 19 | * [x] Other 20 | * [x] macOS 21 | * [x] Raspberry Pi 22 | 23 | ### PHP 版本 24 | 25 | 26 | 27 | * [x] 7.2 28 | * [x] 7.1 29 | * [x] 7.0 30 | * [x] 5.x 31 | 32 | ### 问题描述 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue 3 | about: Create a issue about this project 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | 9 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 10 | 11 | **Describe the solution you'd like** 12 | 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | 21 | Add any other context or screenshots about the feature request here. 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 主要改变(贡献者选项) 4 | 5 | 6 | 7 | # 发布版本(开发者选项) 8 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | 项目支持信息。 2 | 3 | https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-support-resources-to-your-project 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | branches: 5 | - master 6 | tags: 7 | # paths: 8 | # - '*' 9 | # schedule: 10 | # * is a special character in YAML so you have to quote this string 11 | # - cron: '*/15 * * * *' 12 | 13 | name: CI 14 | 15 | jobs: 16 | test: 17 | strategy: 18 | matrix: 19 | php_version: ["8.0.30","8.1.31","8.2.26"] 20 | runs-on: ubuntu-latest 21 | # needs: job 22 | steps: 23 | - uses: actions/checkout@main 24 | with: 25 | fetch-depth: 2 26 | - name: install 27 | uses: khs1994-docker/actions-setup-php@master 28 | with: 29 | php_type: composer 30 | args: | 31 | ls -la vendor || true 32 | php .pcit.php 33 | composer config -g --unset repos.packagist 34 | composer install -q --ignore-platform-reqs 35 | - name: script 36 | uses: khs1994-docker/actions-setup-php@master 37 | with: 38 | php_version: ${{ matrix.php_version }} 39 | job_container_network: ${{ job.container.network }} 40 | args: | 41 | mv /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini.default \ 42 | /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini || true 43 | php -v 44 | env 45 | sleep 30 46 | ping mysql -c 4 || true 47 | ping redis -c 4 || true 48 | php -r "var_dump(new PDO('mysql:host=mysql;dbname=test','root','mytest'));" 49 | vendor/bin/phpunit --coverage-clover=coverage.xml 50 | - name: php-cs-fixer 51 | uses: khs1994-docker/actions-setup-php@master 52 | with: 53 | php_type: php-cs-fixer 54 | args: | 55 | php-cs-fixer fix 56 | - name: after_success 57 | env: 58 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 59 | PHP_VERSION: ${{ matrix.php_version }} 60 | run: | 61 | set -x 62 | mysql -uroot --password=mytest -h 127.0.0.1 -P 13306 -e "show databases" 63 | bash <(curl -s https://codecov.io/bash) -h 64 | bash <(curl -s https://codecov.io/bash) -e PHP_VERSION -n "GitHub Actions" 65 | if: success() 66 | - name: after_failure 67 | run: echo "build error" 68 | if: failure() 69 | - name: always 70 | run: | 71 | set -x 72 | echo "run always" 73 | pwd 74 | docker ps -a 75 | docker logs `docker ps -a --filter "name=mysql" -q` 76 | docker exec -i `docker ps -a --filter "name=mysql" -q` cat /var/log/mysql/error.log 77 | docker logs `docker ps -a --filter "name=redis" -q` 78 | if: always() 79 | working-directory: / 80 | services: 81 | mysql: 82 | image: mysql:5.7.28 83 | ports: 84 | - 13306:3306 85 | env: 86 | MYSQL_DATABASE: test 87 | MYSQL_ROOT_PASSWORD: mytest 88 | volumes: 89 | - mysql-data:/var/lib/mysql 90 | options: -v mysql-data:/var/lib/mysql --restart always --workdir=/ 91 | 92 | redis: 93 | image: redis:7.0.0-alpine 94 | ports: 95 | - 6379:6379 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://github.com/github/gitignore 2 | 3 | .DS_Store 4 | .idea 5 | 6 | # composer 7 | 8 | vendor 9 | composer.lock 10 | auth.json 11 | 12 | # PHP-CS-Fixer 13 | 14 | .php_cs.cache 15 | 16 | # python 17 | 18 | __pycache__ 19 | 20 | # Doctum 21 | 22 | /build 23 | /cache 24 | 25 | # coerage report 26 | 27 | coverage_report 28 | coverage.xml 29 | 30 | .env.* 31 | .env 32 | !.env.example 33 | 34 | # node 35 | node_modules/ 36 | 37 | # public 38 | public/js/ 39 | public/css/ 40 | 41 | # yarn 42 | yarn-error.log 43 | 44 | # npm 45 | package-lock.json 46 | 47 | # laravel 48 | mix-manifest.json 49 | 50 | .phpunit.result.cache 51 | -------------------------------------------------------------------------------- /.pcit.php: -------------------------------------------------------------------------------- 1 | exclude('build') 14 | ->exclude('cache') 15 | ->exclude('vendor') 16 | ->exclude('storage') 17 | // ->notPath('src/Symfony/Component/Translation/Tests/fixtures/resources.php') 18 | ->in(__DIR__) 19 | ->ignoreVCS(true); 20 | 21 | $config = new PhpCsFixer\Config(); 22 | 23 | return $config->setRules([ 24 | '@Symfony' => true, 25 | '@Symfony:risky'=>true, 26 | 'array_syntax' => array('syntax' => 'short'), 27 | 'declare_strict_types' => true, // @PHP70Migration:risky, @PHP71Migration:risky 28 | 'ternary_to_null_coalescing' => true, // @PHP70Migration, @PHP71Migration 29 | 'void_return' => true, // @PHP71Migration:risky 30 | 'ordered_imports' => true, 31 | ]) 32 | ->setCacheFile(__DIR__.'/.php_cs.cache') 33 | ->setFinder($finder) 34 | ->setRiskyAllowed(true) 35 | ; 36 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | # https://styleci.io/ 2 | 3 | risky: true 4 | 5 | preset: Symfony 6 | 7 | enabled: 8 | - strict 9 | - strict_param 10 | - ordered_use 11 | 12 | finder: 13 | name: 14 | - "*.php" 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yaml.schemas": { 3 | "https://github.com/pcit-ce/pcit/raw/master/config/config.schema.json": [ 4 | ".pcit.yml", 5 | ".pcit.yaml", 6 | ".pcit/*.yml", 7 | ".pcit/*.yaml" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CHANGELOG.example.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | ### Added 9 | 10 | ### Changed 11 | 12 | ### Deprecated 13 | 14 | ### Removed 15 | 16 | ### Fixed 17 | 18 | ### Security 19 | 20 | ## [1.0.0] - 2018-08-15 21 | ### Added 22 | 23 | ### Changed 24 | 25 | ### Deprecated 26 | 27 | ### Removed 28 | 29 | ### Fixed 30 | 31 | ### Security 32 | 33 | [Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD 34 | [1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0 35 | [0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | ### Added 9 | - Follow `Keep a Changelog` 10 | 11 | ### Changed 12 | 13 | ### Deprecated 14 | 15 | ### Removed 16 | 17 | ### Fixed 18 | 19 | ### Security 20 | 21 | 22 | ## [18.06.0] - 2018-08-15 23 | ### Added 24 | - Add Sami 25 | - Add PHP-CS-Fixer 26 | - Add khsci 27 | - Support CI Drone CI Style CI 28 | - Support Docker PHP 29 | 30 | ### Changed 31 | - Update Docker Image Tag format 32 | 33 | ### Deprecated 34 | 35 | ### Removed 36 | 37 | ### Fixed 38 | - Fix StyleCI error 39 | 40 | ### Security 41 | 42 | [Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/18.06.0...HEAD 43 | [18.06.0]: https://github.com/khs1994-docker/php-demo/tree/18.06.0 44 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献导引 2 | 3 | 请严格按照以下步骤操作,如有任何问题,请提出 [issue](https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}/issues/new) 4 | 5 | * 在 [GitHub](https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}/fork) 上点击 `fork` 按钮将本仓库 fork 到自己的仓库,如 `yourname/{{ EXAMPLE_GIT_REPO_EXAMPLE }}`,然后 `clone` 到本地。 6 | 7 | ```bash 8 | $ git clone -b dev git@github.com:yourname/{{ EXAMPLE_GIT_REPO_EXAMPLE }}.git 9 | 10 | $ cd {{ EXAMPLE_GIT_REPO_EXAMPLE }} 11 | 12 | # 将项目与上游关联 13 | 14 | $ git remote add upstream git@github.com:{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}.git 15 | ``` 16 | 17 | * 增加内容或者修复错误后提交,并推送到自己的仓库。 18 | 19 | ```bash 20 | $ git add . 21 | 22 | $ git commit -a "Fix issue #1: change helo to hello" 23 | 24 | $ git push origin/dev 25 | ``` 26 | 27 | * 在 [GitHub](https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}) 上提交 `Pull request`,注意请提交到 `dev` 分支。 28 | 29 | * 请定期更新自己仓库。 30 | 31 | ```bash 32 | $ git fetch upstream 33 | 34 | $ git rebase upstream/dev 35 | 36 | $ git push -f origin dev 37 | ``` 38 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 此 Dockerfile 使用了多阶段构建,同时构建了 PHP 及 NGINX 两个镜像 2 | # 3 | # @link https://docs.docker.com/engine/reference/builder/ 4 | # @link https://docs.docker.com/develop/develop-images/multistage-build/ 5 | # @link https://laravel-news.com/multi-stage-docker-builds-for-laravel 6 | # 7 | # 只有 git 打了 tag 才能将对应的镜像部署到生产环境 8 | # 9 | # !! 搜索 /app/EXAMPLE 替换为自己的项目目录 !! 10 | 11 | ARG NODE_VERSION=20.5.1 12 | ARG PHP_VERSION=8.3.12 13 | ARG NGINX_VERSION=1.15.0 14 | ARG DOCKER_HUB_USERNAME=khs1994 15 | 16 | # 1.安装 composer 依赖 17 | FROM ${DOCKER_HUB_USERNAME:-khs1994}/php:${PHP_VERSION}-composer-alpine as composer 18 | 19 | # COPY composer.json composer.lock /app/EXAMPLE/ 20 | COPY composer.json /app 21 | 22 | RUN cd /app \ 23 | && composer install --no-dev \ 24 | --ignore-platform-reqs \ 25 | --prefer-dist \ 26 | --no-interaction \ 27 | --no-scripts \ 28 | --no-plugins 29 | 30 | # 2.将项目打入 PHP 镜像 31 | # $ docker build -t khs1994/php:8.3.12-pro-GIT_TAG-alpine --target=php . 32 | 33 | FROM ${DOCKER_HUB_USERNAME:-khs1994}/php:${PHP_VERSION}-fpm-alpine as php 34 | 35 | COPY . /app/EXAMPLE 36 | COPY --from=composer /app/vendor/ /app/EXAMPLE/vendor/ 37 | 38 | CMD ["php-fpm", "-R"] 39 | 40 | # 5.将 PHP 项目打入 NGINX 镜像 41 | # Nginx 配置文件统一通过 configs 管理,严禁将配置文件打入镜像 42 | # $ docker build -t khs1994/nginx:1.15.0-pro-GIT_TAG-alpine . 43 | 44 | # FROM ${DOCKER_HUB_USERNAME:-khs1994}/nginx:1.15.0-alpine 45 | FROM nginx:${NGINX_VERSION} as nginx 46 | 47 | COPY --from=php /app /app 48 | 49 | ADD https://raw.githubusercontent.com/khs1994-docker/lnmp-nginx-conf-demo/master/wait-for-php.sh /wait-for-php.sh 50 | 51 | RUN rm -rf /etc/nginx/conf.d \ 52 | && chmod +x /wait-for-php.sh 53 | 54 | CMD ["/wait-for-php.sh"] 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2011-2018 khs1994, https://khs1994.com 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.example.md: -------------------------------------------------------------------------------- 1 | # {{ EXAMPLE_GIT_REPO_EXAMPLE }} 2 | 3 | [![GitHub stars](https://img.shields.io/github/stars/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}.svg?style=social&label=Stars)](https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}) [![PHP from Packagist](https://img.shields.io/packagist/php-v/{{ EXAMPLE_COMPOSER_PROJECT_EXAMPLE }}.svg)](https://packagist.org/packages/{{ EXAMPLE_COMPOSER_PROJECT_EXAMPLE }}) [![GitHub (pre-)release](https://img.shields.io/github/release/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}/all.svg)](https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}/releases) [![StyleCI](https://styleci.io/repos/{{ EXAMPLE_STYLECI_ID_EXAMPLE }}/shield?branch=master)](https://styleci.io/repos/{{ EXAMPLE_STYLECI_ID_EXAMPLE }}) 4 | 5 | {{ EXAMPLE_COMPOSER_DESCRIPT_EXAMPLE }} 6 | 7 | ## 微信订阅号 8 | 9 |

10 | 11 |

12 | 13 |

关注项目作者微信订阅号,接收项目最新动态

14 | 15 | ## Installation 16 | 17 | To Use the package, simply: 18 | 19 | ```bash 20 | $ composer require {{ EXAMPLE_COMPOSER_PROJECT_EXAMPLE }} 21 | ``` 22 | 23 | For latest commit version: 24 | 25 | ```bash 26 | $ composer require {{ EXAMPLE_COMPOSER_PROJECT_EXAMPLE }} dev-master 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```php 32 | 26 | 27 |

28 | 29 |

关注项目作者微信订阅号,接收项目最新动态

30 | 31 | ## 说明 32 | 33 | * Laravel 项目,请查看 https://github.com/khs1994-docker/laravel-demo 34 | 35 | ## 初始化 36 | 37 | * 编辑 `.pcit.php` 文件中的常量 38 | 39 | * 执行 `php .pcit.php` 完成替换 40 | 41 | ### 准备 42 | 43 | 建立一个自己的 PHP 项目模板(即 `composer` 包类型为 `project`),里面包含了常用的文件的模板。 44 | 45 | 示例:https://github.com/khs1994-docker/php-demo 46 | 47 | #### 内置文件模板 48 | 49 | | Filename | Description | 50 | | :------------- | :------------- | 51 | | `.github/workflows` | GitHub Actions CI 工具 | 52 | | `.gitattributes` | git 打包时排除文件(例如 测试代码)| 53 | | `.drone.yml` | [`Drone` CI 工具](https://github.com/khs1994-docker/ci) | 54 | | `.editorconfig` | [定义文件格式规则(例如 缩进方式)](https://editorconfig.org/)| 55 | | `.pcit.yml` | [`PCIT` CI 工具](https://ci.khs1994.com) | 56 | | `.php_cs` | [PHP 代码格式化工具](https://github.com/FriendsOfPHP/PHP-CS-Fixer) | 57 | | `.doctum.php` | [PHP 文档生成工具](https://github.com/code-lts/doctum) | 58 | | `.styleci.yml` | [`Style CI` PHP 代码格式化 CI 工具](https://styleci.io/) | 59 | 60 | ## 一、开发 61 | 62 | ### 环境(以下步骤缺一不可) 63 | 64 | * 假设系统中不包含任何 PHP 等程序 65 | 66 | * 启动 Docker CE 67 | 68 | * LNMP [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 69 | 70 | * 将 Docker 化的常用命令所在文件夹加入 `PATH`,具体请查看 [这里](https://github.com/khs1994-docker/lnmp/tree/master/bin)。 71 | 72 | * git 分支 `dev` 73 | 74 | * 使用 Docker 作为 LNMP 环境,实际上大大简化了部署,但配置开发环境需要较多步骤,同时由于 Windows(性能特别差)、macOS(还可以) 运行 Docker 效率较 Linux 差,实际在开发环境是否使用 Docker,请各位自行权衡。 75 | 76 | ### 1. 新建 PHP 项目 77 | 78 | 使用自己的模板项目初始化 `PHP` 项目。 79 | 80 | ```bash 81 | $ cd lnmp/app 82 | 83 | $ lnmp-composer create-project --prefer-dist khs1994/example:dev-master demo 84 | 85 | $ cd demo 86 | 87 | $ git init 88 | 89 | $ git remote add origin git@url.com:username/PROJECT_NAME.git 90 | 91 | $ git checkout -b dev 92 | 93 | $ echo -e "> public/index.php 94 | ``` 95 | 96 | ### 2. 新增 NGINX 配置 97 | 98 | 一个 **PHP 项目**, 一个 **网址**,一个 **NGINX 子配置文件** 99 | 100 | 参考示例配置文件在 `config/nginx` 新建 `*.conf` NGINX 配置文件 101 | 102 | ### 3. 启动 khs1994-docker/lnmp 103 | 104 | ```bash 105 | $ ./lnmp-docker up 106 | 107 | # $ ./lnmp-docker restart 108 | ``` 109 | 110 | ### 4. 浏览器验证 111 | 112 | 浏览器打开页面出现 php 信息 113 | 114 | ### 5. PHPStorm 打开 PHP 项目 115 | 116 | **注意** 打开的是 PHP 项目(避免文件层次过深,IDE 直接打开 PHP 项目),不是 `khs1994-docker/lnmp`! 117 | 118 | 要配置 `khs1994-docker/lnmp` 建议使用另外的文本编辑器。 119 | 120 | > 你可以通过设置 [`APP_ROOT`](https://github.com/khs1994-docker/lnmp/blob/master/docs/development.md#app_root) 变量来实现 `app` 文件夹与 `khs1994-docker/lnmp` 并列。 121 | 122 | ```bash 123 | . 124 | ├── app # 项目文件夹 125 | └── lnmp # khs1994-docker/lnmp 126 | ``` 127 | 128 | ### 6. CLI settings 129 | 130 | 由于 PHP 环境位于 Docker 中,必须进行额外的配置 131 | 132 | 生成 `docker-compose.yml` 133 | 134 | ```bash 135 | # 在 khs1994-docker/lnmp 项目根目录执行 136 | $ lnmp-docker config > docker-compose.yml 137 | ``` 138 | 139 | > [如果使用 Docker Compose V2,请使用 PHPStorm 2021.3 及以上版本](https://youtrack.jetbrains.com/issue/WI-61205) 140 | 141 | `PHPStorm 设置` -> `PHP` -> `CLI Interpreter` -> `点击后边三个点` 142 | -> `点击左上角 + 号` -> `From Docker ...` -> `选择 Docker Compose` 143 | -> `Configuration file(s)` -> `选择 docker-compose.yml(khs1994-docker/lnmp项目根目录)` 144 | -> `Services` -> `选择 workspace` 145 | -> `点击 OK 确认` 146 | 147 | 点击 ok 之后跳转的页面上 `Additionl` -> `Debugger extension`-> 填写 `xdebug` 148 | 149 | 具体请查看 https://github.com/khs1994-docker/lnmp/issues/260#issuecomment-373964173 150 | 151 | 再点击 ok 之后跳转到了 `PHPStorm 设置`-> `PHP` -> `CLI Interpreter` 这个页面 152 | 153 | #### 配置本地路径与容器内路径对应关系 154 | 155 | > 这里的配置 PHPStorm 可能会自动生成,保证正确即可。 156 | 157 | 这里以 Windows 为例,其他系统同理(添加本机路径与容器路径对应关系即可)。 158 | 159 | 由于 Windows 与 Linux 路径表示方法不同,我们必须另外添加路径对应关系。配置本地项目与容器目录之间的路径对应关系。 160 | 161 | 假设本地项目目录位于 `C:/Users/username/app/demo` 对应的容器目录位于 `/app/demo` 162 | 假设本地项目目录位于 WSL2 `\\wsl$\Ubuntu\app\demo` 对应的容器目录位于 `/app/demo` 163 | 164 | `PHPStorm 设置` -> `PHP` -> `Path mappings` 添加一个条目 `C:/Users/username/app/demo` => `/app/demo` 165 | 166 | ### 7. 设置 Xdebug 167 | 168 | 请查看 https://github.com/khs1994-docker/lnmp/blob/master/docs/xdebug.md 169 | 170 | ### 8. 依赖管理 Composer 171 | 172 | 容器化 PHPer 常用命令请查看 https://github.com/khs1994-docker/lnmp/blob/master/docs/command.md 173 | 174 | ```bash 175 | # 引入依赖 176 | $ lnmp-composer require phpunit/phpunit 177 | 178 | # 或安装依赖 179 | $ lnmp-composer install [--ignore-platform-reqs] 180 | ``` 181 | 182 | ### 9. 编写 PHP 代码 183 | 184 | ### 10. 编写 PHPUnit 测试代码 185 | 186 | ### 11. 使用 PHPUnit 测试 187 | 188 | #### 在 PHPStorm 中使用 189 | 190 | `PHPStorm 设置` -> `PHP` ->`Test Frameworks` -> `左上角添加` 191 | -> `PHPUnit by Remote Interpreter` -> `选择第五步添加的 workspace` 192 | -> `点击 OK` -> `PHPUnit Library` -> `选择 Use Composer autoloader` 193 | -> `Path to script` -> 点击右边刷新按钮即可自动识别,或者手动 `填写 /app/PROJECT_NAME/vendor/autoload.php` 194 | -> `点击 OK 确认` 195 | 196 | 在测试函数名单击右键 `run FunName` 开始测试。 197 | 198 | #### 在 命令行 中使用 199 | 200 | ```bash 201 | # 项目目录必须包含 PHPUnit 配置文件 phpunit.xml 202 | $ lnmp-phpunit [参数] 203 | ``` 204 | 205 | ### 12. 本地测试构建 PHP 及 NGINX 镜像 206 | 207 | 此示例将 PHP 代码打入了镜像中,如果你选择将代码放入宿主机,那么无需进行此步骤。两种方法自行取舍。 208 | 209 | 关于代码放到哪里?代码放入宿主机,上线时需要在服务器 pull 代码(或者参考 [git-sync](https://github.com/khs1994-docker/lrew-git-sync) 周期性监听 git 变化并克隆到本地)。代码放入镜像中,上线时直接拉取镜像之后启动容器,无需 pull 代码。 210 | 211 | > 若将 PHP 项目打入镜像,镜像中严禁包含配置文件 212 | 213 | > Docker 镜像必须由 CI 服务器构建,而不是本地人工构建! 214 | 215 | 自行修改 `.env` `docker-compose.yml` 文件,保留所需的 PHP 版本,其他的注释 216 | 217 | ```bash 218 | $ docker compose build php nginx 219 | ``` 220 | 221 | ### 13. 将项目提交到 Git 222 | 223 | ```bash 224 | $ git add . 225 | 226 | $ git commit -m "First" 227 | 228 | $ git push origin dev:dev 229 | ``` 230 | 231 | ## CI/CD 服务搭建 232 | 233 | CI/CD 可以到 [khs1994-docker/ci](https://github.com/khs1994-docker/ci) 查看。 234 | 235 | * Drone (私有化 CI/CD) 236 | 237 | ## 二、测试 238 | 239 | ### CI/CD 服务器收到 Git Push 事件,进行代码测试 240 | 241 | ## 三、开发、测试循环 242 | 243 | ## 四、在 Kubernetes 中部署生产环境 (全自动) 244 | 245 | > 可以在生产环境之前加一个 **预上线** 环境,这里省略。 246 | 247 | ### 1. git 添加 tag,并推送到远程仓库 248 | 249 | ### 2. CI/CD 服务器收到 Git Tag 事件,自动构建镜像并推送镜像到 Docker 仓库(代码在镜像中) 250 | 251 | ### 3. CI/CD 服务器中使用 `Helm` 或 `kustomize` 在 k8s 集群更新服务(代码在镜像中) 252 | 253 | * https://github.com/khs1994-docker/lnmp-k8s/tree/master/helm 254 | 255 | #### 4. 使用 `daemonset` 部署 `gti-sync`(代码不在镜像中) 256 | 257 | 让 **每个节点** 都拥有一份代码,这样就不用关心 `pod` 调度到哪个节点。 258 | 259 | ## BUG 260 | 261 | * https://cn.bing.com/search?q=error+while+parsing+docker-compose+config+failed&qs=n&form=QBRE&sp=-1&pq=error+while+parsing+docker-compose+config+failed&sc=0-48&sk=&cvid=EEF0C7500ECD4BBAAD120B49A52EE153 262 | * https://stackoverflow.com/questions/61520106/pycharm-error-while-parsing-docker-compose-yml-process-docker-compose-confi 263 | -------------------------------------------------------------------------------- /composer.demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ EXAMPLE_COMPOSER_PROJECT_EXAMPLE }}", 3 | "description": "{{ EXAMPLE_COMPOSER_DESCRIPT_EXAMPLE }}", 4 | "keywords": [ 5 | "sdk", 6 | "api" 7 | ], 8 | "homepage": "https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}", 9 | "type": "library", 10 | "license": "MIT", 11 | "authors": [{ 12 | "name": "khs1994", 13 | "email": "khs1994@khs1994.com", 14 | "homepage": "https://khs1994.com" 15 | }], 16 | "support": { 17 | "issues": "https://github.com/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}/issues" 18 | }, 19 | "require": { 20 | "php": ">=7.3.0", 21 | "ext-json": "*", 22 | "ext-curl": "*", 23 | "ext-PDO": "*", 24 | "pimple/pimple": "~3.0", 25 | "doctrine/cache": "^1.6", 26 | "monolog/monolog": "^1.23" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^8.1", 30 | "vlucas/phpdotenv": "~3.0" 31 | }, 32 | "config": { 33 | "php": "7.2.34", 34 | "optimize-autoloader": true, 35 | "sort-packages": true, 36 | "preferred-install": "dist" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}\\": "src/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}\\Tests\\": "tests/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}/" 46 | } 47 | }, 48 | "minimum-stability": "dev", 49 | "prefer-stable": true, 50 | "extra": { 51 | "branch-alias": { 52 | "dev-master": "18.06-dev" 53 | }, 54 | "laravel": { 55 | "providers": [ 56 | "{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}\\Support\\ServiceProvider" 57 | ], 58 | "aliases": { 59 | "{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}": "{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}\\Support\\Facade" 60 | } 61 | } 62 | }, 63 | "scripts": { 64 | "fmt": "php-cs-fixer fix", 65 | "test": "phpunit", 66 | "test:coverage": "phpunit --coverage-clover=coverage.xml", 67 | "install:docker": "composer install --ignore-platform-reqs --prefer-dist --no-interaction --no-scripts --no-plugins" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "khs1994/example", 3 | "description": "Create PHP Project By Composer", 4 | "keywords": [ 5 | "php_project", 6 | "sdk", 7 | "api" 8 | ], 9 | "homepage": "https://github.com/khs1994-php/example", 10 | "type": "project", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "khs1994", 15 | "email": "khs1994@khs1994.com", 16 | "homepage": "https://khs1994.com" 17 | } 18 | ], 19 | "support": { 20 | "issues": "https://github.com/khs1994-php/example/issues" 21 | }, 22 | "require": { 23 | "php": ">=7.3.0", 24 | "ext-curl": "*", 25 | "ext-json": "*", 26 | "ext-PDO": "*", 27 | "pimple/pimple": "~3.0", 28 | "khs1994/curl": "~18.06.0" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^8.1" 32 | }, 33 | "config": { 34 | "php": "7.2.34", 35 | "optimize-autoloader": true, 36 | "sort-packages": true, 37 | "preferred-install": "dist" 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Example\\": "src/Example/" 42 | } 43 | }, 44 | "autoload-dev": { 45 | "psr-4": { 46 | "Example\\Tests\\": "tests/Example/" 47 | } 48 | }, 49 | "scripts": { 50 | "post-create-project-cmd": [ 51 | "@php -r \"copy('README.example.md', 'README.md');\"", 52 | "@php -r \"copy('.gitattributes.example', '.gitattributes');\"", 53 | "@php -r \"copy('CHANGELOG.example.md','CHANGELOG.md');\"", 54 | "@php -r \"unlink('.gitattributes.example');unlink('README.example.md');unlink('CHANGELOG.example.md');\"" 55 | ] 56 | }, 57 | "scripts-descriptions": { 58 | }, 59 | "minimum-stability": "dev", 60 | "prefer-stable": true, 61 | "extra": { 62 | "branch-alias": { 63 | "dev-master": "18.06-dev" 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /config/config-file.php: -------------------------------------------------------------------------------- 1 | env('VALUE', 'default'), 7 | ]; 8 | -------------------------------------------------------------------------------- /deploy/docker-stack.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | services: 4 | nginx: 5 | image: khs1994/nginx:1.15.0-pro-alpine 6 | environment: 7 | - TZ=Asia/Shanghai 8 | ports: 9 | - 18080:80 10 | - 18443:443 11 | networks: 12 | - frontend 13 | depends_on: 14 | - php7 15 | logging: 16 | driver: journald 17 | deploy: 18 | # replicas: 2 19 | placement: 20 | constraints: [node.role == manager] 21 | restart_policy: 22 | condition: any 23 | delay: 5s 24 | max_attempts: 5 25 | window: 123s 26 | update_config: 27 | parallelism: 2 28 | delay: 10s 29 | order: stop-first 30 | labels: 31 | - "com.khs1994.lnmp.demo=true" 32 | - "com.khs1994.lnmp.demo.nginx=true" 33 | configs: 34 | - source: nginx-conf 35 | target: /etc/nginx/nginx.conf 36 | - source: khs1994-com-conf 37 | target: /etc/nginx/conf.d/khs1994.com.conf 38 | secrets: 39 | - source: khs1994-com-crt 40 | target: /etc/nginx/conf.d/ssl/khs1994.com.crt 41 | - source: khs1994-com-key 42 | target: /etc/nginx/conf.d/ssl/khs1994.com.key 43 | 44 | php7: 45 | image: khs1994/php:7.4.33-pro-alpine 46 | environment: 47 | - TZ=Asia/Shanghai 48 | networks: 49 | - frontend 50 | - backend 51 | logging: 52 | driver: journald 53 | deploy: 54 | # replicas: 2 55 | placement: 56 | constraints: [node.role == manager] 57 | restart_policy: 58 | condition: any 59 | delay: 5s 60 | max_attempts: 5 61 | window: 123s 62 | update_config: 63 | parallelism: 2 64 | delay: 10s 65 | order: stop-first 66 | labels: 67 | - "com.khs1994.lnmp.demo=true" 68 | - "com.khs1994.lnmp.demo.php7=true" 69 | configs: 70 | - source: php-ini 71 | target: /usr/local/etc/php.ini 72 | - source: php-fpm-d-zz-docker-conf 73 | target: /usr/local/etc/php-fpm.d/zz-docker.conf 74 | 75 | networks: 76 | backend: 77 | labels: 78 | - "com.khs1994.lnmp.demo=true" 79 | - "com.khs1994.lnmp.demo.backend=true" 80 | frontend: 81 | labels: 82 | - "com.khs1994.lnmp.demo=true" 83 | - "com.khs1994.lnmp.demo.frontend=true" 84 | # 85 | # $ git clone -b config git@github.com:khs1994-docker/php-demo.git ../demo-config 86 | # 87 | configs: 88 | nginx-conf: 89 | file: ../demo-config/nginx/nginx.conf 90 | khs1994-com-conf: 91 | file: ../demo-config/nginx/khs1994.com.conf 92 | php-ini: 93 | file: ../demo-config/php/php.ini 94 | php-fpm-d-zz-docker-conf: 95 | file: ../demo-config/php/zz-docker.conf 96 | 97 | secrets: 98 | khs1994-com-crt: 99 | file: ../demo-config/ssl/khs1994.com.crt 100 | khs1994-com-key: 101 | file: ../demo-config/ssl/khs1994.com.key 102 | -------------------------------------------------------------------------------- /deploy/test.Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # TEST PHP PROJECT BY Docker 3 | # 4 | 5 | ARG PHP_VERSION=8.3.12 6 | ARG GIT_REPO={{ EXAMPLE_GIT_URL_EXAMPLE }}/{{ EXAMPLE_GIT_USERNAME_EXAMPLE }}/{{ EXAMPLE_GIT_REPO_EXAMPLE }}.git 7 | 8 | FROM khs1994/php:${PHP_VERSION}-composer-alpine 9 | 10 | RUN git clone --recursive --depth=1 ${GIT_REPO} /workspace \ 11 | && cd /workspace \ 12 | && composer install -q \ 13 | && composer update -q \ 14 | && vendor/bin/phpunit 15 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 4 | # 警告 compose 文件中包含中文可能会报错,所以阅读之后请删掉中文 5 | # 6 | 7 | # 8 | # docker-compose.yml 文件是为了方便本地测试构建镜像,实际请在 CI 服务器中构建镜像 9 | # 10 | # @link https://docs.docker.com/compose/compose-file/ 11 | # 12 | # 13 | # $ docker compose build 14 | # 15 | 16 | services: 17 | test: 18 | build: 19 | context: . 20 | dockerfile: deploy/test.Dockerfile 21 | args: 22 | - PHP_VERSION=${PHP_VERSION:-8.3.12} 23 | image: ${DOCKER_HUB_USERNAME:-khs1994}/EXAMPLE 24 | 25 | nginx: 26 | build: 27 | context: . 28 | dockerfile: Dockerfile 29 | args: 30 | - NGINX_VERSION=${NGINX_VERSION:-1.15.0} 31 | target: nginx 32 | image: ${DOCKER_HUB_USERNAME:-khs1994}/nginx:${NGINX_VERSION:-1.15.0}-pro-alpine 33 | depends_on: 34 | - php 35 | 36 | php: 37 | build: 38 | context: . 39 | dockerfile: Dockerfile 40 | target: php 41 | args: 42 | - PHP_VERSION=${PHP_VERSION:-8.3.12} 43 | - NODE_VERSION=${NODE_VERSION:-20.5.1} 44 | - NODE_REGISTRY=https://registry.npmmirror.com 45 | image: ${DOCKER_HUB_USERNAME:-khs1994}/php:${PHP_VERSION:-8.3.12}-pro-alpine 46 | -------------------------------------------------------------------------------- /docker-workspace.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | x-common: 4 | &common 5 | # fix me 6 | working_dir: /app/demo 7 | restart: "no" 8 | 9 | services: 10 | workspace: 11 | &workspace 12 | image: khs1994/php:8.3.12-composer-alpine 13 | networks: 14 | - backend 15 | volumes: 16 | - vscode-server:/root/.vscode-server 17 | - vscode-server-insiders:/root/.vscode-server-insiders 18 | - vscode-phpls-cache:/root/.phpls 19 | # fix me 20 | # linux/macOS 21 | - ./:/app/demo 22 | # fix me 将依赖挂载到数据卷 23 | # - vendor:/app/demo/vendor 24 | 25 | # - /var/lib/app/demo:/app/demo 26 | 27 | # composer 28 | - type: volume 29 | source: composer-cache-data 30 | target: /tmp/composer/cache 31 | - type: bind 32 | source: ./.devcontainer/composer.config.json 33 | target: /tmp/composer/config.json 34 | # - type: bind 35 | # source: ./.devcontainer/composer.auth.json 36 | # target: /tmp/composer/auth.json 37 | 38 | # php 39 | - type: bind 40 | source: ./.devcontainer/docker-php.ini 41 | target: /usr/local/etc/php/conf.d/docker-php.ini 42 | - type: bind 43 | source: ./.devcontainer/php-cli.ini 44 | target: /usr/local/etc/php/php-cli.ini 45 | - ./.devcontainer/php-log:/var/log/php 46 | 47 | # node 48 | # 如果你修改了 .npmrc 中的路径,请同步更改这里的数据卷映射关系 49 | - type: bind 50 | source: ./.devcontainer/.npmrc 51 | target: /usr/local/etc/npmrc 52 | - npm-global-data:/tmp/node/npm 53 | - npm-cache-data:/tmp/node/.npm 54 | command: /bin/sh -c "while sleep 1000; do :; done" 55 | environment: 56 | APP_ENV: ${APP_ENV:-development} 57 | TZ: Asia/Shanghai 58 | 59 | vscode-remote-container-workspace: 60 | << : *workspace 61 | ports: 62 | # 如果 vsCode 运行在容器中,必须开放 9003 端口供 xdebug 连接 63 | # xdebug port 64 | - 9003:9003 65 | 66 | composer: 67 | << : 68 | - *workspace 69 | - *common 70 | image: "khs1994/php:8.3.12-composer-alpine" 71 | command: [] # install | update 72 | 73 | npm: 74 | << : 75 | - *workspace 76 | - *common 77 | image: node:20.5.1-alpine 78 | entrypoint: npm 79 | command: [] # install | "run","dev" | 80 | 81 | networks: 82 | backend: 83 | external: true 84 | name: lnmp_backend 85 | 86 | volumes: 87 | composer-cache-data: 88 | external: true 89 | name: lnmp_composer-cache-data 90 | vscode-server: 91 | vscode-server-insiders: 92 | vscode-phpls-cache: 93 | vendor: 94 | # 或者复用其他数据卷 95 | # external: true 96 | # name: lnmp_laravel_vendor 97 | npm-global-data: 98 | npm-cache-data: 99 | external: true 100 | name: lnmp_npm-cache-data 101 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }} 6 | 7 | 8 | 9 | 10 | ./src 11 | 12 | ./src/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}/Console 13 | ./src/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}/Support/ServiceProvider.php 14 | ./src/{{ EXAMPLE_FOLDER_NAME_EXAMPLE }}/Support/Facade.php 15 | 16 | 17 | 18 | 19 | 20 | dont-test 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !demo.html 4 | !index.php 5 | !.user.ini 6 | -------------------------------------------------------------------------------- /public/.user.ini: -------------------------------------------------------------------------------- 1 | ; user_ini.filename = .user.ini 2 | ; user_ini.cache_ttl = 300 3 | ; 5min 4 | 5 | ; 以上两项请到 php.ini 中设置,无法在此文件设置 6 | ; https://www.php.net/manual/zh/configuration.changes.modes.php 7 | ; https://www.php.net/manual/zh/ini.core.php 8 | 9 | ; https://segmentfault.com/a/1190000011552335 10 | 11 | ; 在此文件中只能配置以下类型的 ini 12 | ; PHP_INI_PERDIR 和 PHP_INI_USER 13 | 14 | ; 此文件中设置的值无需重启 php,每隔 user_ini.cache_ttl 秒扫描并生效 15 | 16 | ; default is 128M 17 | memory_limit = 256M 18 | 19 | ; open_basedir = /app/demo 20 | 21 | ; 除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件(由 user_ini.filename 设置,默认为 .user.ini ), 22 | ; 从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。 23 | ; 如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。 24 | ; 25 | ; 假如 web 根目录为 /app/demo/public 26 | ; 访问 127.0.0.1/t/t/1.php 会加载 27 | ; 此文件具有最高优先级,即三个目录中的 .user.ini 配置了同一个指令,此文件中设置的值有效 28 | ; /app/demo/public/t/t/.user.ini 29 | ; /app/demo/public/t/.user.ini 30 | ; /app/demo/public/.user.ini 31 | ; 32 | -------------------------------------------------------------------------------- /public/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LNMP Demo 5 | 6 |
7 | 8 | phpinfo()
9 | 10 |
11 | 12 | Memcached
13 | MongoDB
14 | PDO-MySQL
15 | PostgresSQL
16 | RabbitMQ
17 | Redis
18 | 19 |
20 | 21 |

ClusterKit

22 | 23 | Redis 集群版
24 | 25 | Redis 主从版
26 | 27 | Mysql
28 | 29 | Memcached
30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | arg 值为 [1,2,3] 18 | // {--id=*} cli --id=1 --id=2 19 | 20 | protected $description = 'command description'; 21 | 22 | public function handle(): void 23 | { 24 | $arg = $this->argument('arg'); 25 | 26 | $option = $this->hasOption('option'); 27 | 28 | try { 29 | $output = 1; 30 | 31 | // $this->ask('question','default'); 32 | 33 | // $password = $this->secret('What is the password?'); 34 | 35 | // $this->confirm('Do you wish to continue?') 36 | 37 | // $name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']); 38 | 39 | // $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default); 40 | 41 | $this->line($output); 42 | // ->info 43 | // ->comment 44 | // ->question 45 | 46 | // 输出表格 47 | // $this->table(['a', 'b'], [1, 2]); 48 | 49 | // 调用其他命令 50 | // $this->call('email:send', [ 51 | // 'user' => 1, '--queue' => 'default' 52 | // ]); 53 | 54 | // 阻止输出 55 | // $this->callSilent('email:send', [ 56 | // 'user' => 1, '--queue' => 'default' 57 | // ]); 58 | } catch (Exception $e) { 59 | $this->error($e->getMessage()); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Example/Example.php: -------------------------------------------------------------------------------- 1 | register(); 14 | * 15 | * $container['a'] = new A(); 16 | * 17 | * $a = $container['a']; 18 | * 19 | * @property string bbb 20 | * method getValue() 21 | */ 22 | class Example extends Container 23 | { 24 | /** 25 | * 服务提供器数组. 26 | */ 27 | protected $providers = [ 28 | Providers\BBBProvider::class, 29 | ]; 30 | 31 | /** 32 | * 注册服务提供器. 33 | */ 34 | private function registerProviders(): void 35 | { 36 | // 取得服务提供器数组. 37 | $array = array_merge($this->providers, $this['config']->get('providers', [])); 38 | foreach ($array as $k) { 39 | $this->register(new $k()); 40 | } 41 | } 42 | 43 | public function __construct(array $config = []) 44 | { 45 | parent::__construct(); 46 | 47 | // 在容器中注入类 48 | $this['config'] = new Support\Config($config); 49 | 50 | // 注册一个服务提供者 51 | $this->register(new Providers\BBBProvider()); 52 | 53 | // 注册服务提供器 54 | $this->registerProviders(); 55 | } 56 | 57 | /** 58 | * 通过调用属性,获取对象 59 | * 60 | * @param $name 61 | * @param $arguments 62 | * 63 | * @throws Exception 64 | * 65 | * @return mixed 66 | */ 67 | public function __get($name) 68 | { 69 | // $example->调用不存在属性时 70 | if (isset($this[$name])) { 71 | return $this[$name]; 72 | } 73 | 74 | throw new Exception('Not found'); 75 | } 76 | 77 | /** 78 | * 通过调用方法,获取对象 79 | */ 80 | public function bbb() 81 | { 82 | return $this['bbb']; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Example/Exception/ExampleException.php: -------------------------------------------------------------------------------- 1 | get('a')); 19 | }; 20 | 21 | // BBB 依赖 AAA,将 AAA 注入 BBB 22 | $pimple['bbb'] = function ($app) { 23 | return new BBB($app['bbb.aaa']); 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Example/Providers/CacheProvider.php: -------------------------------------------------------------------------------- 1 | aaa = $aaa; 14 | } 15 | 16 | public function returnConfig() 17 | { 18 | return $this->aaa; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Example/Service/BBB.php: -------------------------------------------------------------------------------- 1 | aaa = $aaa; 17 | } 18 | 19 | public function getValue() 20 | { 21 | return $this->aaa->returnConfig(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Example/Support/Config.php: -------------------------------------------------------------------------------- 1 | config = $config; 14 | } 15 | 16 | public function get($name) 17 | { 18 | return $this->config[$name] ?? []; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Example/Support/Facade.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($configPath, 'config-file'); 30 | // $this->loadRoutesFrom(__DIR__.'/routes.php'); 31 | // $this->loadMigrationsFrom(__DIR__.'/path/to/migrations'); 32 | // $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); 33 | $this->app->singleton('example', function ($app) { 34 | return $this->connection($app); 35 | }); 36 | 37 | $this->app->alias('example', Example::class); 38 | // $this->app->bind('example', function () { 39 | // return new Example(); 40 | // }); 41 | } 42 | 43 | /** 44 | * 在注册后进行服务的启动。 45 | */ 46 | public function boot(): void 47 | { 48 | $configPath = __DIR__.'/../../../config/config-file.php'; 49 | $this->publishes([$configPath => $this->getConfigPath()], 'config'); 50 | // $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier'); 51 | // $this->publishes([ 52 | // __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'), 53 | // ]); 54 | // $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier'); 55 | // $this->publishes([ 56 | // __DIR__.'/path/to/views' => resource_path('views/vendor/courier'), 57 | // ]); 58 | // if ($this->app->runningInConsole()) { 59 | // $this->commands([ 60 | // Console\ExampleCommand::class, 61 | // ]); 62 | // } 63 | // $this->publishes([ 64 | // __DIR__.'/path/to/assets' => public_path('vendor/courier'), 65 | // ], 'public'); 66 | } 67 | 68 | /** 69 | * Get the config path. 70 | * 71 | * @return string 72 | */ 73 | protected function getConfigPath() 74 | { 75 | return config_path('config-file.php'); 76 | } 77 | 78 | /** 79 | * 获取提供器提供的服务。 80 | * 81 | * @return array 82 | */ 83 | public function provides() 84 | { 85 | return ['example']; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !{{ EXAMPLE_FOLDER_NAME_EXAMPLE }} 3 | !Example 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /tests/Example/ExampleTest.php: -------------------------------------------------------------------------------- 1 | getTest(); 12 | } 13 | 14 | public function testExample(): void 15 | { 16 | $test = $this->example()->bbb->getValue(); 17 | 18 | $this->assertEquals(1, $test); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/Example/ExampleTestCase.php: -------------------------------------------------------------------------------- 1 | load(); 19 | } 20 | 21 | if (!(self::$test instanceof Example)) { 22 | self::$test = new Example(['a' => 1]); 23 | } 24 | 25 | return self::$test; 26 | } 27 | } 28 | --------------------------------------------------------------------------------