mirror of
https://github.com/codeguy/php-the-right-way.git
synced 2025-08-13 17:23:58 +02:00
Merge branch 'gh-pages' of github.com:codeguy/php-the-right-way into gh-pages
This commit is contained in:
19
_posts/01-06-01-Common-Directory-Structure.md
Normal file
19
_posts/01-06-01-Common-Directory-Structure.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Common Directory Structure
|
||||
isChild: true
|
||||
anchor: common_directory_structure
|
||||
---
|
||||
|
||||
## Common Directory structure {#common_directory_structure_title}
|
||||
|
||||
A common question among those starting out with writing programs for the web is, "where do I put my stuff?" Over the years, this answer has consistently been "where the `DocumentRoot` is." Although this answer is not complete, it's a great place to start.
|
||||
|
||||
For security reasons, configuration files should not be accessible by a site's visitors; therefore, public scripts are kept in a public directory and private configurations and data are kept outside of that directory.
|
||||
|
||||
For each team, CMS, or framework one works in, a standard directory structure is used by each of those entities. However, if one is starting a project alone, knowing which filesystem structure to use can be daunting.
|
||||
|
||||
[Paul M. Jones] has done some fantastic research into common practices of tens of thousands of github projects in the realm of PHP. He has compiled a standard file and directory structure, the [Standard PHP Package Skeleton], based on this research. In this directory structure, `DocumentRoot` should point to `public/`, unit tests should be in the `tests/` directory, and third party libraries, as installed by [composer], belong in the `vendor/` directory. For other files and directories, abiding by the [Standard PHP Package Skeleton] will make the most sense to contributors of a project.
|
||||
|
||||
[Paul M. Jones]: https://twitter.com/pmjones
|
||||
[Standard PHP Package Skeleton]: https://github.com/php-pds/skeleton
|
||||
[Composer]: /#composer_and_packagist
|
@@ -31,9 +31,9 @@ don't try this if your project will contain more than a couple of pages.
|
||||
|
||||
The most classic way and often taken as reference for i18n and l10n is a [Unix tool called `gettext`][gettext]. It dates
|
||||
back to 1995 and is still a complete implementation for translating software. It is pretty easy to get running, while
|
||||
it still sports powerful supporting tools. It's about Gettext we will be talking here. Also, to help you not get messy
|
||||
over the command-line, we will be presenting a great GUI application that can be used to easily update your l10n source
|
||||
files.
|
||||
it still sports powerful supporting tools. We will talk about Gettext in more detail below. If you would prefer to not
|
||||
have to get your hands dirty with the command line, we will also be presenting a great GUI application that can be used
|
||||
to easily update your l10n source files.
|
||||
|
||||
### Other tools
|
||||
|
||||
@@ -41,6 +41,9 @@ There are common libraries used that support Gettext and other implementations o
|
||||
install or sport additional features or i18n file formats. In this document, we focus on the tools provided with the
|
||||
PHP core, but here we list others for completion:
|
||||
|
||||
- [aura/intl][aura-intl]: Provides internationalization (I18N) tools, specifically package-oriented per-locale message
|
||||
translation. It uses array formats for message. Does not provide a message extractor, but does provide advanced
|
||||
message formatting via the `intl` extension (including pluralized messages).
|
||||
- [oscarotero/Gettext][oscarotero]: Gettext support with an OO interface; includes improved helper functions, powerful
|
||||
extractors for several file formats (some of them not supported natively by the `gettext` command), and can also export
|
||||
to other formats besides `.mo/.po` files. Can be useful if you need to integrate your translation files into other parts
|
||||
@@ -400,6 +403,7 @@ After including those new rules in the `.po` file, a new scan will bring in your
|
||||
[3166-1]: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
||||
[rare]: https://www.gnu.org/software/gettext/manual/gettext.html#Rare-Language-Codes
|
||||
[func_format]: https://www.gnu.org/software/gettext/manual/gettext.html#Language-specific-options
|
||||
[aura-intl]: https://github.com/auraphp/Aura.Intl
|
||||
[oscarotero]: https://github.com/oscarotero/Gettext
|
||||
[symfony]: https://symfony.com/doc/current/components/translation.html
|
||||
[zend]: https://docs.zendframework.com/zend-i18n/translation
|
||||
|
@@ -15,19 +15,66 @@ separate from our objects. In terms of Dependency Injection, this means loosenin
|
||||
instantiating them elsewhere in the system.
|
||||
|
||||
For years, PHP frameworks have been achieving Inversion of Control, however, the question became, which part of control
|
||||
are you inverting, and where to? For example, MVC frameworks would generally provide a super object or base controller
|
||||
are we inverting, and where to? For example, MVC frameworks would generally provide a super object or base controller
|
||||
that other controllers must extend to gain access to its dependencies. This **is** Inversion of Control, however,
|
||||
instead of loosening dependencies, this method simply moved them.
|
||||
|
||||
Dependency Injection allows us to more elegantly solve this problem by only injecting the dependencies we need, when we
|
||||
need them, without the need for any hard coded dependencies at all.
|
||||
|
||||
### Dependency Inversion Principle
|
||||
### S.O.L.I.D.
|
||||
|
||||
Dependency Inversion Principle is the "D" in the S.O.L.I.D set of object oriented design principles that states one
|
||||
should *"Depend on Abstractions. Do not depend on concretions."*. Put simply, this means our dependencies should be
|
||||
interfaces/contracts or abstract classes rather than concrete implementations. We can easily refactor the above example
|
||||
to follow this principle.
|
||||
#### Single Responsibility Principle
|
||||
|
||||
The Single Responsibility Principle is about actors and high-level architecture. It states that “A class should have
|
||||
only one reason to change.” This means that every class should _only_ have responsibility over a single part of the
|
||||
functionality provided by the software. The largest benefit of this approach is that it enables improved code
|
||||
_reusability_. By designing our class to do just one thing, we can use (or re-use) it in any other program without
|
||||
changing it.
|
||||
|
||||
#### Open/Closed Principle
|
||||
|
||||
The Open/Closed Principle is about class design and feature extensions. It states that “Software entities (classes,
|
||||
modules, functions, etc.) should be open for extension, but closed for modification.” This means that we should design
|
||||
our modules, classes and functions in a way that when a new functionality is needed, we should not modify our existing
|
||||
code but rather write new code that will be used by existing code. Practically speaking, this means that we should write
|
||||
classes that implement and adhere to _interfaces_, then type-hint against those interfaces instead of specific classes.
|
||||
|
||||
The largest benefit of this approach is that we can very easily extend our code with support for something new without
|
||||
having to modify existing code, meaning that we can reduce QA time, and the risk for negative impact to the application
|
||||
is substantially reduced. We can deploy new code, faster, and with more confidence.
|
||||
|
||||
#### Liskov Substitution Principle
|
||||
|
||||
The Liskov Substitution Principle is about subtyping and inheritance. It states that “Child classes should never break
|
||||
the parent class’ type definitions.” Or, in Robert C. Martin’s words, “Subtypes must be substitutable for their base
|
||||
types.”
|
||||
|
||||
For example, if we have a `FileInterface` interface which defines an `embed()` method, and we have `Audio` and `Video`
|
||||
classes which both implement the `embed()` method, then we can expect that the usage of the `embed()` method will always
|
||||
do the thing that we intend. If we later create a `PDF` class or a `Gist` class which implement the `FileInterface`
|
||||
interface, we will already know and understand what the `embed()` method will do. The largest benefit of this approach
|
||||
is that we have the ability to build flexible and easily-configurable programs, because when we change one object of a
|
||||
type (e.g., `FileInterface`) to another we don't need to change anything else in our program.
|
||||
|
||||
#### Interface Segregation Principle
|
||||
|
||||
The Interface Segregation Principle (ISP) is about _business-logic-to-clients_ communication. It states that “No client
|
||||
should be forced to depend on methods it does not use.” This means that instead of having a single monolithic interface
|
||||
that all conforming classes need to implement, we should instead provide a set of smaller, concept-specific interfaces
|
||||
that a conforming class implements one or more of.
|
||||
|
||||
For example, a `Car` or `Bus` class would be interested in a `steeringWheel()` method, but a `Motorcycle` or `Tricycle`
|
||||
class would not. Conversely, a `Motorcycle` or `Tricycle` class would be interested in a `handlebars()` method, but a
|
||||
`Car` or `Bus` class would not. There is no need to have all of these types of vehicles implement support for both
|
||||
`steeringWheel()` as well as `handlebars()`, so we should break-apart the source interface.
|
||||
|
||||
#### Dependency Inversion Principle
|
||||
|
||||
The Dependency Inversion Principle is about removing hard-links between discrete classes so that new functionality can
|
||||
be leveraged by passing a different class. It states that one should *"Depend on Abstractions. Do not depend on
|
||||
concretions."*. Put simply, this means our dependencies should be interfaces/contracts or abstract classes rather than
|
||||
concrete implementations. We can easily refactor the above example to follow this principle.
|
||||
|
||||
{% highlight php %}
|
||||
<?php
|
||||
@@ -50,7 +97,7 @@ class MysqlAdapter implements AdapterInterface {}
|
||||
|
||||
There are several benefits to the `Database` class now depending on an interface rather than a concretion.
|
||||
|
||||
Consider that you are working in a team and the adapter is being worked on by a colleague. In our first example, we
|
||||
Consider that we are working in a team and the adapter is being worked on by a colleague. In our first example, we
|
||||
would have to wait for said colleague to finish the adapter before we could properly mock it for our unit tests. Now
|
||||
that the dependency is an interface/contract we can happily mock that interface knowing that our colleague will build
|
||||
the adapter based on that contract.
|
||||
|
@@ -87,7 +87,7 @@ class FooModel
|
||||
|
||||
{% highlight php %}
|
||||
<?php foreach ($fooList as $row): ?>
|
||||
<?= $row['field1'] ?> - <?= $row['field1'] ?>
|
||||
<li><?= $row['field1'] ?> - <?= $row['field1'] ?></li>
|
||||
<?php endforeach ?>
|
||||
{% endhighlight %}
|
||||
|
||||
|
@@ -87,7 +87,8 @@ rewritten like this:
|
||||
|
||||
{% highlight php %}
|
||||
<?php
|
||||
echo isset($foo['bar']) ? $foo['bar'] : '';
|
||||
//Null Coalescing Operator
|
||||
echo $foo['bar'] ?? '';
|
||||
{% endhighlight %}
|
||||
|
||||
One instance where error suppression might make sense is where `fopen()` fails to find a file to load. You could check
|
||||
|
@@ -14,6 +14,8 @@ libraries useful for any preferred approach taken.
|
||||
* [Mockery] is a Mock Object Framework which can be integrated with [PHPUnit] or [PHPSpec]
|
||||
* [Prophecy] is a highly opinionated yet very powerful and flexible PHP object mocking framework. It's integrated with
|
||||
[PHPSpec] and can be used with [PHPUnit].
|
||||
* [php-mock] is a library to help to mock PHP native functions.
|
||||
* [Infection] is a PHP implementation of [Mutation Testing] to help to measure the effectiveness of your tests.
|
||||
|
||||
|
||||
[Selenium]: https://www.seleniumhq.org/
|
||||
@@ -22,3 +24,6 @@ libraries useful for any preferred approach taken.
|
||||
[PHPUnit]: https://phpunit.de/
|
||||
[PHPSpec]: https://www.phpspec.net/
|
||||
[Prophecy]: https://github.com/phpspec/prophecy
|
||||
[php-mock]: https://github.com/php-mock/php-mock
|
||||
[Infection]: https://github.com/infection/infection
|
||||
[Mutation Testing]: https://en.wikipedia.org/wiki/Mutation_testing
|
||||
|
@@ -20,6 +20,13 @@ another source of packages which ideally have little to no dependencies on other
|
||||
For example, you can use the [FuelPHP Validation package], without needing to use the FuelPHP framework itself.
|
||||
|
||||
* [Aura]
|
||||
* CakePHP Components
|
||||
* [Collection]
|
||||
* [Database]
|
||||
* [Datasource]
|
||||
* [Event]
|
||||
* [I18n]
|
||||
* [ORM]
|
||||
* [FuelPHP]
|
||||
* [Hoa Project]
|
||||
* [Symfony Components]
|
||||
@@ -46,3 +53,9 @@ components best decoupled from the Laravel framework are listed above._
|
||||
[Eloquent ORM]: https://github.com/illuminate/database
|
||||
[Queue]: https://github.com/illuminate/queue
|
||||
[Illuminate components]: https://github.com/illuminate
|
||||
[Collection]: https://github.com/cakephp/collection
|
||||
[Database]: https://github.com/cakephp/database
|
||||
[Datasource]: https://github.com/cakephp/datasource
|
||||
[Event]: https://github.com/cakephp/event
|
||||
[I18n]: https://github.com/cakephp/i18n
|
||||
[ORM]: https://github.com/cakephp/orm
|
||||
|
Reference in New Issue
Block a user