fix some typos

This commit is contained in:
lubiana 2022-05-21 01:19:14 +02:00 committed by Andre Lubian
parent 2fbbd082f2
commit 62cff766db
7 changed files with 41 additions and 41 deletions

View file

@ -23,7 +23,7 @@ like this:
}, },
``` ```
Now run `composer update` in your console and it will be installed. Now run `composer update` in your console, and it will be installed.
Another way to install packages is to simply type "composer require filp/whoops" into your terminal at the project root, Another way to install packages is to simply type "composer require filp/whoops" into your terminal at the project root,
i that case composer automatically installs the package and updates your composer.json-file. i that case composer automatically installs the package and updates your composer.json-file.
@ -33,7 +33,7 @@ ideally a [PSR-4](http://www.php-fig.org/psr/psr-4/) autoloader. Composer alread
only have to add a `require __DIR__ . '/../vendor/autoload.php';` to your `Bootstrap.php`. only have to add a `require __DIR__ . '/../vendor/autoload.php';` to your `Bootstrap.php`.
**Important:** Never show any errors in your production environment. A stack trace or even just a simple error message **Important:** Never show any errors in your production environment. A stack trace or even just a simple error message
can help someone to gain access to your system. Always show a user friendly error page instead and send an email to can help someone to gain access to your system. Always show a user-friendly error page instead and send an email to
yourself, write to a log or something similar. So only you can see the errors in the production environment. yourself, write to a log or something similar. So only you can see the errors in the production environment.
For development that does not make sense though -- you want a nice error page. The solution is to have an environment For development that does not make sense though -- you want a nice error page. The solution is to have an environment

View file

@ -4,7 +4,7 @@
I have added some more helpers to my composer.json that help me with development. As these are scripts and programms I have added some more helpers to my composer.json that help me with development. As these are scripts and programms
used only for development they should not be used in a production environment. Composer has a specific sections in its used only for development they should not be used in a production environment. Composer has a specific sections in its
file called "dev-dependencies", everything that is required in this section does not get installen in production. file called "dev-dependencies", everything that is required in this section does not get installed in production.
Let's install our dev-helpers and i will explain them one by one: Let's install our dev-helpers and i will explain them one by one:
`composer require --dev phpstan/phpstan symfony/var-dumper slevomat/coding-standard symplify/easy-coding-standard rector/rector` `composer require --dev phpstan/phpstan symfony/var-dumper slevomat/coding-standard symplify/easy-coding-standard rector/rector`
@ -15,7 +15,7 @@ Phpstan is a great little tool, that tries to understand your code and checks if
create bad defined interfaces and structures. It also helps in finding logic-errors, dead code, access to array elements create bad defined interfaces and structures. It also helps in finding logic-errors, dead code, access to array elements
that are not (or not always) available, if-statements that always are true and a lot of other stuff. that are not (or not always) available, if-statements that always are true and a lot of other stuff.
A very simple example would be a small functions that takes a DateTime-Object and prints it in a human readable format. A very simple example would be a small functions that takes a DateTime-Object and prints it in a human-readable format.
```php ```php
/** /**
@ -45,9 +45,9 @@ Line Bootstrap.php
``` ```
The second error is something that "declare strict-types" already catches for us, but the first error is something that The second error is something that "declare strict-types" already catches for us, but the first error is something that
we usually would not discover easily without speccially looking for this errortype. we usually would not discover easily without specially looking for this error-type.
We can add a simple configfile called `phpstan.neon` to our project so that we do not have to specify the errorlevel and We can add a simple config file called `phpstan.neon` to our project so that we do not have to specify the error level and
path everytime we want to check our code for errors: path everytime we want to check our code for errors:
```yaml ```yaml
@ -59,7 +59,7 @@ parameters:
now we can just call `./vendor/bin/phpstan analyze` and have the same setting for every developer working in our project now we can just call `./vendor/bin/phpstan analyze` and have the same setting for every developer working in our project
With this settings we have already a great setup to catch some errors before we execute the code, but it still allows us With this settings we have already a great setup to catch some errors before we execute the code, but it still allows us
some silly things, therefore we want to add install some packages that enforce rules that are a little bit more strict. some silly things, therefore we want to add install some packages that enforce rules that are a little stricter.
```shell ```shell
composer require --dev phpstan/extension-installer composer require --dev phpstan/extension-installer
@ -67,7 +67,7 @@ composer require --dev phpstan/phpstan-strict-rules thecodingmachine/phpstan-str
``` ```
During the first install you need to allow the extension installer to actually install the extension. The second command During the first install you need to allow the extension installer to actually install the extension. The second command
installs some more strict rulesets and activates them in phpstan. installs some more strict rules and activates them in phpstan.
If we now rerun phpstan it already tells us about some errors we have made: If we now rerun phpstan it already tells us about some errors we have made:
@ -84,9 +84,9 @@ Line Bootstrap.php
``` ```
The last two Errors are caused by the Exception we have used to test the ErrorHandler in the last chapter if we remove The last two Errors are caused by the Exception we have used to test the ErrorHandler in the last chapter if we remove
that we should be able to fix that. The first error is something we could fix, but I dont want to focus on that specific that we should be able to fix that. The first error is something we could fix, but I don't want to focus on that specific
problem right now. Phpstan gives us the option to ignore some errors and handle them later. If for example we are working problem right now. Phpstan gives us the option to ignore some errors and handle them later. If for example we are working
on an old legacy codebase and wanted to add static analysis to it but cant because we would get 1 Million error messages on an old legacy codebase and wanted to add static analysis to it but can't because we would get 1 Million error messages
everytime we use phpstan, we could add all those errors to a list and tell phpstan to only bother us about new errors we everytime we use phpstan, we could add all those errors to a list and tell phpstan to only bother us about new errors we
are adding to our code. are adding to our code.
@ -128,7 +128,7 @@ which basically does the same has in my experience some more Rules available tha
But we are going to use neither of those tools directly and instead choose the [Easy Coding Standard](https://github.com/symplify/easy-coding-standard) But we are going to use neither of those tools directly and instead choose the [Easy Coding Standard](https://github.com/symplify/easy-coding-standard)
which allows us to combine rules from both mentioned tools, and also claims to run much faster. You could check out the which allows us to combine rules from both mentioned tools, and also claims to run much faster. You could check out the
documentation and decide on your own coding standard. Or use the one provided by me, which is base on PSR-12 but adds documentation and decide on your own coding standard. Or use the one provided by me, which is base on PSR-12 but adds
some highly opiniated options. First create a file 'ecs.php' and either add your own configuration or copy the my some highly opiniated options. First create a file 'ecs.php' and either add your own configuration or copy the
prepared one: prepared one:
```php ```php
@ -288,8 +288,8 @@ with lots of parameters by hand all the time, so I added a few lines to my `comp
}, },
``` ```
that way I can just type "composer" followed by the command name in the root of my project. if i want to start the that way I can just type "composer" followed by the command name in the root of my project. if I want to start the
php devserver I can just type "composer serve" and dont have to type in the hostname, port and targetdirectory all the php dev server I can just type "composer serve" and don't have to type in the hostname, port and target directory all the
time. time.
You could also configure PhpStorm to automatically run these commands in the background and highlight the violations You could also configure PhpStorm to automatically run these commands in the background and highlight the violations
@ -297,7 +297,7 @@ directly in the file you are currently editing. I personally am not a fan of thi
flow when programming and always forces me to be absolutely strict even if I am only trying out an idea for debugging. flow when programming and always forces me to be absolutely strict even if I am only trying out an idea for debugging.
My workflow is to just write my code the way I currently feel and that execute the phpstan and the fix scripts before My workflow is to just write my code the way I currently feel and that execute the phpstan and the fix scripts before
commiting and pushing the code. There is a [highly opiniated blogpost](https://tomasvotruba.com/blog/2019/06/24/do-you-use-php-codesniffer-and-php-cs-fixer-phpstorm-plugin-you-are-slow-and-expensive/) committing and pushing the code. There is a [highly opiniated blogpost](https://tomasvotruba.com/blog/2019/06/24/do-you-use-php-codesniffer-and-php-cs-fixer-phpstorm-plugin-you-are-slow-and-expensive/)
discussing that topic further. That you can read. But in the end it boils down to what you are most comfortable with. discussing that topic further. That you can read. But in the end it boils down to what you are most comfortable with.
[<< previous](03-error-handler.md) | [next >>](05-http.md) [<< previous](03-error-handler.md) | [next >>](05-http.md)

View file

@ -19,7 +19,7 @@ the laminas/laminas-diactoros package as i am an old time fan of the laminas (pr
Some alternatives are [slim-psr7](https://github.com/slimphp/Slim-Psr7), [Guzzle](https://github.com/guzzle/psr7) and a Some alternatives are [slim-psr7](https://github.com/slimphp/Slim-Psr7), [Guzzle](https://github.com/guzzle/psr7) and a
[lot more](https://packagist.org/providers/psr/http-message-implementation) are available for you to choose from. [lot more](https://packagist.org/providers/psr/http-message-implementation) are available for you to choose from.
Symfony ships its own Request and Response objects that do not implement the psr-7 interfaces. Therefore i will not use Symfony ships its own Request and Response objects that do not implement the psr-7 interfaces. Therefore, I will not use
that in this tutorial, but if you understand how the psr-7 interfaces work you should have no problem in understanding that in this tutorial, but if you understand how the psr-7 interfaces work you should have no problem in understanding
the [symfony http-foundation](https://symfony.com/doc/current/components/http_foundation.html#request). the [symfony http-foundation](https://symfony.com/doc/current/components/http_foundation.html#request).
@ -38,7 +38,7 @@ $response->getBody()->write('The Uri is: ' . $request->getUri()->getPath());
This sets up the `Request` and `Response` objects that you can use in your other classes to get request data and send a response back to the browser. This sets up the `Request` and `Response` objects that you can use in your other classes to get request data and send a response back to the browser.
In order to actually add content to the response you have to access the Body-Streamobject of the Response and use the In order to actually add content to the response you have to access the body stream object of the Response and use the
write()-Method on that object. write()-Method on that object.
@ -66,7 +66,7 @@ $response = $response->withStatus(200);
$response = $response->withAddedHeader('Content-type', 'application/json'); $response = $response->withAddedHeader('Content-type', 'application/json');
``` ```
If you have ever struggled with Mutationproblems in an DateTime-Object you might understand why the standard has been If you have ever struggled with Mutation-problems in an DateTime-Object you might understand why the standard has been
defined this way. defined this way.
But if you have been keeping attention you might argue that the following line should not work if the request object is But if you have been keeping attention you might argue that the following line should not work if the request object is
@ -80,7 +80,7 @@ The response-body implements a stream interface which is immutable for some reas
[meta-document](https://www.php-fig.org/psr/psr-7/meta/#why-are-streams-mutable). For me the important thing is to be [meta-document](https://www.php-fig.org/psr/psr-7/meta/#why-are-streams-mutable). For me the important thing is to be
aware of the problems that can occur with mutable objects. Here is a small [Blogpost](http://andrew.carterlunn.co.uk/programming/2016/05/22/psr-7-is-not-immutable.html) that gives some context. Beware that the Middleware-Example in aware of the problems that can occur with mutable objects. Here is a small [Blogpost](http://andrew.carterlunn.co.uk/programming/2016/05/22/psr-7-is-not-immutable.html) that gives some context. Beware that the Middleware-Example in
the post is based on a deprecated middleware standard. But more on middlewares will be discussed in later chapters. the post is based on a deprecated middleware standard. But more on middlewares will be discussed in later chapters.
I for one am happy about that fact, as it saves me from writing at least 3 lines of code whenever i want to add content I, for one, am happy about that fact, as it saves me from writing at least 3 lines of code whenever i want to add content
to a response object. to a response object.
```php ```php
@ -90,7 +90,7 @@ $response = $response->withBody($body);
``` ```
Right now we are just outputting the Response-Body without any headers or http-status. So we need to expand our Right now we are just outputting the Response-Body without any headers or http-status. So we need to expand our
output-logic a little bit more. Replace the line that echos the response-body with the following: output-logic a little more. Replace the line that echos the response-body with the following:
```php ```php
foreach ($response->getHeaders() as $name => $values) { foreach ($response->getHeaders() as $name => $values) {
@ -114,7 +114,7 @@ echo $response->getBody();
``` ```
This code is still fairly simple and there is a lot more stuff that can be considered when emitting a response to a This code is still fairly simple and there is a lot more stuff that can be considered when emitting a response to a
webbrowser, if you want a more complete solution you can take a look at the [httpsoft/http-emitter](https://github.com/httpsoft/http-emitter/blob/master/src/SapiEmitter.php) package on github. browser, if you want a more complete solution you can take a look at the [httpsoft/http-emitter](https://github.com/httpsoft/http-emitter/blob/master/src/SapiEmitter.php) package on github.
Remember that the object is only storing data, so if you set multiple status codes before you send the response, only the last one will be applied. Remember that the object is only storing data, so if you set multiple status codes before you send the response, only the last one will be applied.

View file

@ -63,10 +63,10 @@ dispatcher gets called and the appropriate part of the switch statement will be
we collect any variable parameters of the route, store them in the request parameterbag and call the handler callable. we collect any variable parameters of the route, store them in the request parameterbag and call the handler callable.
If the route dispatcher returns a wrong value in the first entry of the routeMatch array we handle it the same as a 404. If the route dispatcher returns a wrong value in the first entry of the routeMatch array we handle it the same as a 404.
This setup might work for really small applications, but once you start adding a few routes your bootstrap file will This setup might work for tiny applications, but once you start adding a few routes your bootstrap file will
quickly get cluttered. So let's move them out into a separate file. quickly get cluttered. So let's move them out into a separate file.
Create a new directory in you projectroot named 'config' and add a 'routes.php' file with the following content; Create a new directory in you project root named 'config' and add a 'routes.php' file with the following content;
```php ```php
<?php declare(strict_types = 1); <?php declare(strict_types = 1);
@ -95,7 +95,7 @@ $dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback);
This is already an improvement, but now all the handler code is in the `routes.php` file. This is not optimal, so let's fix that in the next part. This is already an improvement, but now all the handler code is in the `routes.php` file. This is not optimal, so let's fix that in the next part.
Of course we now need to add the 'config' folder to the configuration files of our Of course, we now need to add the 'config' folder to the configuration files of our
devhelpers so that they can scan that directory as well. dev helpers so that they can scan that directory as well.
[<< previous](05-http.md) | [next >>](07-dispatching-to-a-class.md) [<< previous](05-http.md) | [next >>](07-dispatching-to-a-class.md)

View file

@ -33,8 +33,8 @@ final class Hello implements \Psr\Http\Server\RequestHandlerInterface
``` ```
You can see that we implement the [RequestHandlerInterface](https://github.com/php-fig/http-server-handler/blob/master/src/RequestHandlerInterface.php) You can see that we implement the [RequestHandlerInterface](https://github.com/php-fig/http-server-handler/blob/master/src/RequestHandlerInterface.php)
that has a 'handle'-Method with requires a Requestobject as its parameter and returns a Responseobject. For now this is that has a 'handle'-Method with requires a Request object as its parameter and returns a Response-object. For now this is
fine, but we may have to change our approach later. In anyway it is good to know about this interface as we will implement fine, but we may have to change our approach later. In any way it is good to know about this interface as we will implement
it in some other parts of our application as well. In order to use that Interface we have to require it with composer: it in some other parts of our application as well. In order to use that Interface we have to require it with composer:
`composer require psr/http-server-handler`. `composer require psr/http-server-handler`.
@ -77,9 +77,9 @@ Now if you visit `http://localhost:1235/` everything should work. If not, go bac
And of course don't forget to commit your changes. And of course don't forget to commit your changes.
Something that still bothers me is the fact, that we do have classes for our Handlers, but the Error responses are still Something that still bothers me is the fact, that we do have classes for our Handlers, but the Error responses are still
generated in the routing-matching section and not in special classes. Also we have still left some cases to chance, for generated in the routing-matching section and not in special classes. Also, we have still left some cases to chance, for
example if there is an error in creating our RequestHandler class or if the call to the 'handle' function fails. We still example if there is an error in creating our RequestHandler class or if the call to the 'handle' function fails. We still
have our whoopsie error-handler but i like to be more explicit in my control flow. have our whoopsie error-handler, but I like to be more explicit in my control flow.
In order to do that we need to define some special Exceptions that we can throw and catch explicitly. Lets add a new In order to do that we need to define some special Exceptions that we can throw and catch explicitly. Lets add a new
Folder/Namespace to our src directory called Exceptions. And define the classes NotFound, MethodNotAllowed and Folder/Namespace to our src directory called Exceptions. And define the classes NotFound, MethodNotAllowed and
@ -99,7 +99,7 @@ final class NotFound extends Exception{}
Use that example to create a MethodNotAllowedException.php and InternalServerErrorException.php as well. Use that example to create a MethodNotAllowedException.php and InternalServerErrorException.php as well.
After you have created those we update our Routercode to use the new Exceptions. After you have created those we update our Router code to use the new Exceptions.
```php ```php
try { try {

View file

@ -7,7 +7,7 @@ want to switch to a more powerfull Http-Implementation later, or need to create
we would need to edit every one of our request handlers to call a different constructor of the class. we would need to edit every one of our request handlers to call a different constructor of the class.
The sane option is to use [inversion of control](http://en.wikipedia.org/wiki/Inversion_of_control). This means that The sane option is to use [inversion of control](http://en.wikipedia.org/wiki/Inversion_of_control). This means that
instead of giving the class the responsiblity of creating the object it needs, you just ask for them. This is done instead of giving the class the responsibility of creating the object it needs, you just ask for them. This is done
with [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection). with [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection).
If this sounds a little complicated right now, don't worry. Just follow the tutorial and once you see how it is If this sounds a little complicated right now, don't worry. Just follow the tutorial and once you see how it is

View file

@ -4,13 +4,13 @@
In the last chapter we rewrote our Actions to require the response-objet as a constructor parameter, and provided it In the last chapter we rewrote our Actions to require the response-objet as a constructor parameter, and provided it
in the dispatcher section of our `Bootstrap.php`. As we only have one dependency this works really fine, but if we have in the dispatcher section of our `Bootstrap.php`. As we only have one dependency this works really fine, but if we have
different classes with different dependencies our bootstrap file gets complicated quite quickly. Lets look at an example different classes with different dependencies our bootstrap file gets complicated quite quickly. Let's look at an example
to explain the problem and work on a solution. to explain the problem and work on a solution.
#### Adding a clock service #### Adding a clock service
Lets assume that we want to show the current time in our Hello action. We could easily just call use one of the many Lets assume that we want to show the current time in our Hello action. We could easily just call use one of the many
ways to get the current time directly in the handle-method, but lets create a separate class and interface for that so ways to get the current time directly in the handle-method, but let's create a separate class and interface for that so
we can later configure and switch our implementation. we can later configure and switch our implementation.
We need a new 'Service\Time' namespace, so lets first create the folder in our 'src' directory 'src/Service/Time'. We need a new 'Service\Time' namespace, so lets first create the folder in our 'src' directory 'src/Service/Time'.
@ -45,7 +45,7 @@ final class SystemClock implements Clock
} }
``` ```
Now we can require the Clockinterface as a depencency in our controller and use it to display the current time. Now we can require the Clock interface as a dependency in our controller and use it to display the current time.
```php ```php
<?php declare(strict_types=1); <?php declare(strict_types=1);
@ -82,7 +82,7 @@ final class Hello implements RequestHandlerInterface
} }
``` ```
But if we try to access the corresponding route in the webbrowser we get an error: But if we try to access the corresponding route in the browser we get an error:
> Too few arguments to function Lubian\NoFramework\Action\Hello::__construct(), 1 passed in /home/lubiana/PhpstormProjects/no-framework/app/src/Bootstrap.php on line 62 and exactly 2 expected > Too few arguments to function Lubian\NoFramework\Action\Hello::__construct(), 1 passed in /home/lubiana/PhpstormProjects/no-framework/app/src/Bootstrap.php on line 62 and exactly 2 expected
Our current problem is, that we have two Actions defined, which both have different constructor requirements. That means, Our current problem is, that we have two Actions defined, which both have different constructor requirements. That means,
@ -114,7 +114,7 @@ I mostly define an Interface or a fully qualified classname as an ID. That way I
the Clock interface or an Action class and get an object of that class or an object implementing the given Interface. the Clock interface or an Action class and get an object of that class or an object implementing the given Interface.
For the sake of this tutorial we will put a new file in our config folder that returns an anonymous class implementing For the sake of this tutorial we will put a new file in our config folder that returns an anonymous class implementing
the containerinterface. the container-interface.
In this class we will configure all services required for our application and make them accessible via the get($id) In this class we will configure all services required for our application and make them accessible via the get($id)
method. method.
@ -164,13 +164,13 @@ return new class () implements \Psr\Container\ContainerInterface {
}; };
``` ```
Here I have declared a services array, that has a class- or interfacename as the keys, and the values are short Here I have declared a services array, that has a class- or interface name as the keys, and the values are short
closures that return an Object of the defined class or interface. The `has` method simply checks if the given id is closures that return an Object of the defined class or interface. The `has` method simply checks if the given id is
defined in our services array, and the `get` method calls the closure defined in the array for the given id key and then defined in our services array, and the `get` method calls the closure defined in the array for the given id key and then
returns the result of that closure. returns the result of that closure.
To use the container we need to update our Bootstrap.php. Firstly we need to get an instance of our container, and then To use the container we need to update our Bootstrap.php. Firstly we need to get an instance of our container, and then
use that to create our Request-Object as well as the Dispatcher. So remove the manual instantion of those objects and use that to create our Request-Object as well as the Dispatcher. So remove the manual instantiation of those objects and
replace that with the following code: replace that with the following code:
```php ```php
@ -201,7 +201,7 @@ assert($handler instanceof RequestHandlerInterface);
If you now open the `/hello` route in your browser everything should work again! If you now open the `/hello` route in your browser everything should work again!
#### Using Autowiring #### Using Auto wiring
If you take a critical look at the services array you might see that we need to manually define how our Hello- and If you take a critical look at the services array you might see that we need to manually define how our Hello- and
Other-Action are getting constructed. This is quite repetitive, as we have already declared what objects to create Other-Action are getting constructed. This is quite repetitive, as we have already declared what objects to create
@ -215,9 +215,9 @@ functionality ourselves, or just try to use a library that takes care of that fo
You can query the composer database to find all [libraries that implment the container interface](https://packagist.org/providers/psr/container-implementation). You can query the composer database to find all [libraries that implment the container interface](https://packagist.org/providers/psr/container-implementation).
I choose the [PHP-DI](https://packagist.org/packages/php-di/php-di) container, as it is easy to configure and provides some very [powerfull features](https://php-di.org/#autowiring) I choose the [PHP-DI](https://packagist.org/packages/php-di/php-di) container, as it is easy to configure and provides some very [powerfull features](https://php-di.org/#autowiring)
out of the box, and also solves the autowiring problem. out of the box, and also solves the auto wiring problem.
Lets rewrite our `container.php` file to use the PHP-DI container and only define the Services the Container cannot Let's rewrite our `container.php` file to use the PHP-DI container and only define the Services the Container cannot
automatically build. automatically build.
```php ```php
@ -237,7 +237,7 @@ return $builder->build();
``` ```
As the PHP-DI container that is return by the `$builder->build()` method implements the same container interface as our As the PHP-DI container that is return by the `$builder->build()` method implements the same container interface as our
previously used ad-hoc container we won't need to update the our Bootstrap file and everything still works. previously used ad-hoc container we won't need to update the Bootstrap file and everything still works.
[<< previous](08-inversion-of-control.md) | [next >>](10-invoker.md) [<< previous](08-inversion-of-control.md) | [next >>](10-invoker.md)