Merge branch 'gh-pages' of github.com:codeguy/php-the-right-way into gh-pages

This commit is contained in:
Josh Lockhart
2018-06-20 10:34:22 -04:00
7 changed files with 101 additions and 12 deletions

View 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

View File

@@ -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

View File

@@ -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. Martins 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.

View File

@@ -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 %}

View File

@@ -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

View File

@@ -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

View File

@@ -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