www.phparch.com April 2018 Volume 17 - Issue 4 Testing in Practice

PHPUnit Worst Practices Easier Mocking with Mockery Testing Strategy With the Help of Static Analysis Evolved PHP

ALSO INSIDE

Artisanal: Community Corner: Education Station: Authentication with What’s the Fuss About Build an API, Part One Laravel Serverless? finally{}: The Dev Lead Trenches: Security Corner: On the Creativity of Ongoing Education PHP Isolation in Programmers Production PHP ApplicationSample Hosting PHP[TEK] 2018 The Premier PHP Conference 13th Annual Edition MAY 31ST – JUNE 1ST Downtown Atlanta

Full scheduleSample announced!

Talks from experts at MailChimp, Salesforce, Etsy, Google, Oracle, Pantheon and many more! tek.phparch.com April 2018 Volume 17 - Issue 4

Features Columns 2 Editorial: Testing in Practice 3 PHPUnit Worst Practices Oscar Merida

Victor Bolshov 27 Artisanal: Authentication with Laravel Joe Ferguson

8 Easier Mocking with 31 The Dev Lead Trenches: Ongoing Education Mockery, Part 1 Chris Tankersley Robert Basic 34 Security Corner: PHP Isolation in Production Eric Mann 14 Testing Strategy With the 36 Education Station: Build an API, Part One Help of Static Analysis Edward Barnard 44 March Happenings Ondrej Mirtes 46 Community Corner: Sample What’s the Fuss About 20 Evolved PHP Serverless? James Titcumb

Chris Pitt 48 finally{}: On the Creativity of Programmers Eli White

Editor-in-Chief: Subscriptions Although all possible care has been placed in assuring the Oscar Merida Print, digital, and corporate subscriptions are available. Visit accuracy of the contents of this magazine, including all https://www.phparch.com/magazine to subscribe or email associated source code, listings and figures, the publisher Editor: Kara Ferguson [email protected] for more information. assumes no responsibilities with regards of use of the information contained herein or in all associated material. Advertising To learn about advertising and receive the full prospectus, [architect], php[a], the php[architect] logo, musketeers. contact us at [email protected] today! me, LLC and the musketeers.me, LLC logo are trademarks of musketeers.me, LLC. Managing Partners Kevin Bruce, Oscar Merida, Sandy Smith Contact Information: General mailbox: [email protected] php[architect] is published twelve times a year by: Editorial: [email protected] musketeers.me, LLC 201 Adams Avenue Print ISSN 1709-7169 Alexandria, VA 22301, USA Digital ISSN 2375-3544 Copyright © 2018—musketeers.me, LLC All Rights Reserved FEATURE

Testing Strategy With the Help of Static Analysis Ondrej Mirtes When developing an application, our aim as software developers is to make sure it does what it ought to do and to keep the number of defects as low as possible. We should also strive to make our lives easier, to counter external circumstances like tight deadlines and ever-changing requirements causing the exact opposite. That’s why we’re always looking out for tools and practices to help us with our jobs. In this article, I’d like to introduce you to the concept of type safety and how it can improve the reliability and stability of your code. Once your code is more type-safe, and that fact is verified by automated tools, you can cherry-pick which parts of your application need extensive unit tests and where you can rely just on well-defined types.

Type System And Type Safety additional benefits—not only that we know what we can pass to the function, it also tells us what operations (methods) the To have a type system means to communicate what kinds object offers. of values travel through code clearly. Since not all values can I’m not saying scalar values are never enough, and you be treated the same, the more we know about them, the better. should always use objects, but every time you’re tempted If you currently don’t have any type hints at all, adding infor- to type hint a string, go through a mental exercise on what mation to the code whether you’re accepting int, float, string could go wrong with the input. Do I want to allow an empty or bool can go a long way. string? What about non-ASCII characters? Instead of putting But when a function declares it accepts an integer, does validation logic into a function that does something with a it really mean any integer? Just a positive integer? Or only scalar value, create a special object and put the validation a limited set of values, like hours in a day or minutes in an logic in its constructor. You don’t have to write the valida- hour? Trimming down possible inputs reduces undefined tion in each place where the object is accepted anymore, and behavior. Going down this road further means you have you also don’t have to test the function’s behavior for inval- to start type-hinting your own objects which comes with id inputs provided the object cannot be created with invalid Samplevalues. Listing 1 For example, you might have a function which accepts a 1. class EmailAddress string for an email address, but you must check if the email 2. { is valid. 3. /** @var string */ function sendMessage(string $email) { 4. private $email; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { 5. throw new \InvalidArgumentException( 6. public function __construct(string $email) { "Invalid email string" 7. if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { ); 8. throw new \InvalidArgumentException( } 9. "Not a valid email string" // do something 10. ); } 11. } 12. $this->email = $email; Instead, you can flip it and make your function—and any 13. } other one—explicitly expect an EmailAddress object as in 14. Listing 1. 15. public function getAddress(): string { 16. return $this->email; Once your codebase is filled with type hints, IDEs and stat- 17. } ic analyzers know more about it, and you can benefit from 18. } them. For example, if you annotate a property with a phpDoc 19. (unfortunately there’s no native support for property types 20. function sendMessage(EmailAddress $email) { yet), these tools can verify: 21. // do something 22. } 14 \ April 2018 \ www.phparch.com Testing Strategy With the Help of Static Analysis

1. The type hint is valid, and the class There’s no machine-readablephpDoc conventions, employ custom exists. connection between hasAddress() and plugins and analyze loops and branches 2. You’re assigning only objects of this getAddress() in type hints. The knowl- to infer as many types as possible. type to it. edge the above code will always work One of these tools is PHPStan1; it’s 3. You’re calling only methods avail- is available only in developer’s head or open-source and free to use (disclaim- able on the type-hinted class. by closely inspecting the source code er: I’m the main developer of PHPStan.) of the class. You might object that this Other similar tools are Phan2, Exakat3, /** example is too simple, and everyone 4 * @var Address and Psalm . understands what’s going on, but there */ Besides obvious errors, it can also are much more complex examples like private $address; point out code that can be simplified this in the wild. For example, a Product like always false comparisons using object that has every property nullable The same benefits stemming from ===, !==, instanceof, or isset() on because they can be empty while the type hints are also applicable to func- never defined variables, duplicate keys Product is being configured in the tion/method parameters and return in literal arrays, unused constructor content management system, but once types. There’s always the write part parameters, and much more. Because it’s published and available for purchase (what is returned from a method) and running a comprehensive analysis on on the site, they are guaranteed to be the read part (what the caller does with an existing codebase for the first time filled out. Any code that works only the returned value). can result in an overwhelming list of with published products has to make potential issues, PHPStan supports $value !== checks in order to Listen to the Types gradual checking. Its goal is to enable comply with the type system. Types can also give you subtle developers to start using the tool as feedback about the design of your A solution to this problem is gener- soon as possible and to feel like they’re application—learn to listen to it. One ally not to reuse objects for different leveling up in a video game. use cases. You can represent published such case is inappropriate interfac- vendor/bin/phpstan analyse src/ es—when you’re implementing an products with a PublishedProduct class interface, and you’re forced to throw where every getter is non-nullable. If you run the PHPStan executable an exception from half of the methods without any flags, it will run the basic you have to add to the class, the inter- Tools for Finding Type level zero by default, checking only face isn’t designed well and will usually System Defects (a.K.a. types it’s completely sure about, like benefit from separating into several Bugs) methods called statically and on $this. smaller ones. Using such an interface It does not even check types passed to in production code is dangerous—by Because it is interpreted at runtime, method arguments until level five (only implementing it, you’re promising it’s PHP itself does not discover type the number of passed arguments is safe to pass the object somewhere the system defects in advance because that’s checked on lower levels), but it definite- interface is type-hinted but calling its usually a job of the compiler. A program ly finds a lot of issues in between. methods will throw unexpected excep- Samplein C# or Java will refuse to execute if PHPStan is extensible—you can there’s a problem like an undefined tions. write custom rules specific to your variable, calling an unknown meth- Another type of feedback is making codebase and also extensions describ- od or passing an argument of a wrong use of information that’s unknown to ing behavior of magic __call, __get, type somewhere deep in the code. In the type system. If the developer knows and __set methods. You can also write PHP, if there’s an error like that in the and takes advantage of something that a so-called “dynamic return type exten- third step of the checkout process, the isn’t obvious from looking at the type sion” for describing return types of developer (or the user) will find it when hints, like checking a condition in functions or methods which vary based they execute that line of code during advance and knowing what a method on various conditions like types of testing or in production. But thanks to will return based on the result. It can arguments passed to the function or the the latest advancements in the language make the tools fail with a false positive: type of object the method is called on. itself, like scalar and nullable type hints, if ($user->hasAddress()) { There are already plenty of extensions it’s now easier to be sure about types of // getAddress() return typehint available for popular frameworks like many variables and other expressions // is ?Address Doctrine, Symfony, or PHPUnit. $address = $user->getAddress(); just by looking at the code without the

need to execute it. 1 PHPStan: // potentially dangerous - // $address might be null That’s where static analyzers come https://github.com/phpstan/phpstan echo $address->getStreet(); into play. They gather all available infor- 2 Phan: http://github.com/phan/phan } mation about the code—besides native 3 Exakat: https://exakat.io type hints, they understand common 4 Psalm: https://getpsalm.org

www.phparch.com \ April 2018 \ 15 Testing Strategy With the Help of Static Analysis

How to Save Time with a much harder not only for static analyz- in a method usually means only some Static Analyzer ers but for developers too. nullability combinations are valid. PHP is naturally very benevolent Consider this example which sets a date We already established there is a lot about the handling of data which usual- range on an object: of value to gain from the type system. ly goes against safety and predictability. public function setDates( But how can we use it to save precious Many of the tips I’m sharing below are \DateTimeImmutable $from, time and resources? When testing a about cutting down the space of possi- \DateTimeImmutable $to); PHP application, whether manually ble outcomes, resulting in simpler code. or automatically, developers spend a If a requirement comes that the dates lot of their time discovering mistakes Tips for More Strongly-Typed should also be removable, you might be tempted to solve it this way: that wouldn’t even compile in other Code languages, leaving less time for testing public function setDates( actual business logic. Typically, there’s 1. Don’t Hide Errors ?\DateTimeImmutable $from, duplicate effort because some bugs are ?\DateTimeImmutable $to); discovered by both static analysis and Turn on reporting and logging of all by unit tests as in Figure 1. errors using error_reporting(E_ALL);. But that means you can call the Especially notices (e.g., E_NOTICE), method with only a single date, leaving Since tests must be written by regardless of their name, are the most the object in an inconsistent state. humans and represent code as any severe errors that can occur—things other, they are very costly—not only $object->setDates( like undefined variables or missing during the initial development but for new \DateTimeImmutable('2017-10-11'), array keys are reported as notices. null); maintenance as well. Our goal should $object->setDates( be to make those two sets disjoint, so 2. Enable Strict Types null, we don’t write any test which can be new \DateTimeImmutable('2017-12-07') Use declare(strict_types = 1); covered by static analysis. And while ); on top of every file. This ensures only we’re at it, we can try to make the blue values of compatible types can be circle as big as possible so the type You can prevent this from happen- passed to function arguments, basical- system gains more power and is able to ing by adding an additional check to ly that "dogs" does not get cast to 0. I find most bugs on its own. the method body, but that bypasses the can’t recommend this mode enough; type system and relies only on runtime One could object we’ll save time its impact can be compared to turning correctness. Try to distinguish between by not writing redundant tests, but on notice reporting. The per-file basis different use cases not by making the that time will get used up by writing allows for gradual integration—turn it parameters nullable but by adding classes, adding type hints, thinking on in a few selected files and observe another method: about interfaces and structuring the the effects, rinse and repeat until it’s on code differently to benefit from the public function setDates( in all the files. \DateTimeImmutable $from, type system as much as possible. To \DateTimeImmutable $to); counter the objection, I’d argue tests 3. EncapsulateSample All Code public function removeDates(); get written only to prevent bugs, but All code should be encapsulated in solid and strong types have benefits classes or at least functions. Having 5. Avoid associative arrays. reaching much further—they improve all the variables created in the local When type-hinting an array, the readability and provide necessary scope helps tremendously with know- code does not communicate that the communication and documentation ing their type. For the same reason, you developer should pass an array with a about how the code works. Without shouldn’t use global variables. Instead specific structure. And the function any types, the orientation in the code is of procedural scripts stitched together which accepts the array cannot rely on via include and using variables appear- the array having specific keys and that Figure 1. Venn diagram ing out of nowhere, everything is neatly the keys are of a certain type. Arrays organized and obvious. are not a good fit for passing values 4. Avoid Unnecessary Nullables around if you want maintainability Avoid nullables where they’re not and a reliable type system. Use objects necessary. Nullable parameters and which enforce and communicate what return types complicate things. You they contain and do. The only excep- have to write if statements to prevent tion where arrays are fine is when they manipulating with null. More branch- represent a collection of values of the es signify there’s more code to test. same type. This can be communicated Having multiple nullable parameters with a phpDoc and is enforceable using static analysis.

16 \ April 2018 \ www.phparch.com Testing Strategy With the Help of Static Analysis

/** input validation. Instead, work with place needs to get fixed. In contrast, * @param User[] $users specific values and write a specific when an integration or even a UI test */ public function setUsers( comparison of what you’re trying to fails, we have no idea where to look. A array $users achieve. Don’t use empty when asking third party service could be down, our ); about an empty array, use count($ar- database could have changed, or maybe ray) === 0. Don’t use it for detecting we just moved some button 10 pixels 6. Avoid Dynamic Code an because it would not to the right and changed its text. Unit accept "0", write $str !== '' instead. tests shouldn’t have any dependencies Avoid dynamic code like outside of the code. They should not $this->$propertyName new or 9. Use only Booleans in conditions connect to the database, access the $className() . Also, don’t use reflection If you look at the table summarizing filesystem and send anything over the in your business logic. It’s fine if your loose comparisons, the true and false network. Since they focus on testing framework or library uses reflection columns summarize what happens just the application code, they tend to internally to achieve what you’re asking when a bare value is put into a condi- be very fast. Having some integration it to do but stay away from it when writ- tion, and the result can surprise you. tests help, mainly for things that can’t ing ordinary code. Do not step outside Again, use explicit comparison against be tested with unit tests because of their the comforts of the type system into the the value you’re looking for. Tip: nature, but unit tests should form the dangerous territory of reflection. PHPStan’s extension phpstan/phpstan- big and solid base of your test pyramid. 7. Avoid Loose Comparisons strict-rules enforces this and other Application code can be divided into rules for strictly-typed code. Don’t use loose comparisons like == two main types: wiring and business logic. Wiring is what holds the appli- or !=. When comparing different types, What Tests Do We Need? PHP will try to guess what you mean cation together; controllers, facades, which leads to very unexpected results. All the tips above were of local char- passing values along, getters and setters. I circled the most surprising ones in acter—how to improve specific places Business logic is what justifies the Figure 2. Did you know "0" equals to in your code to get the most out of the existence of our application and what false? Or that array() equals to null? type system. What I’m about to share we’re paid to do, such as mathematical now impacts the architecture of the operations, filtering, validation, parsers, Instead, use strict comparisons like whole application and makes opinion- managing state transitions, etc. A stat- === and !==. They require both the ated decisions about what has to be ic analyzer will tell you if you’re calling types and the values to match. In case unit-tested and where the static analy- an undefined method, but it can’t know of objects, === will return true only if it’s sis of the type system is sufficient. you should have used ceil() instead of the same instance on both sides. In case floor() or that you should have written of DateTime objects, where the compar- First, let’s clarify why I think a unit that if condition the other way around. ison operators are overloaded by the test is the most valuable kind of test language, using == was acceptable. and what criteria it needs to meet. Unit So how can one justify the existence When PHP 7.1 introduced microsec- tests focus on testing one small unit, of wiring? In modern applications, Sampleusually a class or a function. When a there’s a lot of it, and we’re better for it. onds, it broke a lot of code. I recommend comparing DateTime instances by first unit test fails, we know exactly which Wiring makes reusability possible. We calling ->format(), stating the required precision and then compare the strings Figure 2. Loose comparison table using strict operators. Avoid Empty Comparisons A similar case of loose typing is the empty construct. Here’s a list of values considered empty: • "" (an empty string) • 0 (an integer) • 0.0 (a float) • "0" • null • false • an empty array This makes empty unusable for any

www.phparch.com \ April 2018 \ 17 Testing Strategy With the Help of Static Analysis

Figure 3. Grow Listing 2

1. class Calculator 2. { 3. /** 4. * @param Foo $foo 5. * @param Bar[] $bars 6. */ 7. public function calculate(Foo $foo, 8. array $bars): CalculatorResult { 9. // ... 10. } 11. } can extract common pieces of code in a correctly architectured applica- allows me to represent data as objects— and call them from multiple places. It tion shouldn’t be necessary because they can be type-hinted, constructed improves readability by splitting code it’s white-box testing and by definition by hand for the purpose of unit tests, into smaller chunks. Thanks to wiring, dependent on the inner structure of the and contain methods which guarantee our code is more maintainable. tested code, therefore more prone to consistent modifications. But because of its nature, testing it breaking. With tests, you can measure code can become tedious and boring. Test- Instead, separate the business logic a coverage, a percentage of executed lines ing setters, getters, and whole classes to a different class and design its public of code during test runs. I propose whose only purpose is to forward interface to receive all the data it needs a similar metric for static analysis. If values to subsequent layers does not for its job. This class does not need to having more type hints means we can yield a lot of revealed errors and is not perform any database queries or other rely on the code more, there should be a very economical. Once we have type side effects. It will receive data from the number associated with that. I propose hints for everything and employ a static real source in production and manually the term “type coverage” to signify how analyzer, it should be enough to verify created data in tests. You can write a lot many variables and other expressions the wiring code works as expected. of simple unit tests without any mock- result in mixed and which have a more The role of the entry point to an ing and test every edge case since you specific type. application, like a controller, is to sani- saved a lot of time by not testing the tize all incoming data and pass them wiring code (Listing 2)! Closing Words further down the line as well-defined This is also the reason why I like using Static analyser should be in the tool and validated types. If you allow strong ORMs like Doctrine. They get a bad belt of every PHP programmer. Simi- types to grow through your application, reputation because people use them for larly to a package manager and unit it becomes much more solid and stati- the wrongSample reasons. You shouldn’t look testing framework, it’s an indispensable cally verifiable as shown in Figure 3. to an ORM to generate SQL queries for tool for making quality applications. It Unit tests should focus on business you because the tool doesn’t know what should run besides tests on a contin- logic. A classic mistake is to interweave you will need in advance, resulting in uous integration server because its business logic with data querying, poor performance. You shouldn’t use function is similar - to prevent bugs. making the job of a unit test much an ORM so you can switch to a differ- Once we get used to the feedback from harder: ent database engine one day. Quite the type system, we can concentrate our the opposite—you’re missing out if function doSomething(int $id): void { testing efforts in places where the static $foo = $this->someRepository you’re not using the advanced features analyzer can’t know how the right code ->getById($id); of your database of choice. The reason should look. In the rest of the applica- // business logic performed on $foo. why I like to use an ORM is because it tion, it has us covered. $bars = $this->otherRepository ->getAllByFoo($foo); // business logic performed on $foo Ondřej works as the CTO at Slevomat.cz, moving between // and $bars product and software development. He enjoys quality assur- } ance and frequent deployment of innovations for the end users. He shares his experience at conferences across Europe, offers With this code structure, you don’t his expertise as a consultant, and organizes trainings. He also have any other option than to mock in created PHPStan, a popular static analyzer that focuses on order to provide the interesting lines you finding bugs in code without running it. @OndrejMirtes want to test with some data. Mocking

18 \ April 2018 \ www.phparch.com a php[architect] guide

Discover how to secure your applications against many of the vulnerabilities exploited by attackers.

Security is an ongoing process not something to add right before your app launches. In this book, you’ll learn how to write secure PHP applications from first principles. Why wait until your site is attacked or your data is breached? Prevent your exposure by being aware of the ways a malicious user might hijack your web site or API. Security Principles for PHP Applications is a comprehensive guide. This book contains examples of vulnerable code side-by-side with solutions to harden it. Organized around the 2017 OWASP Top Ten list, topics cover include: • Injection Attacks • Authentication and Session Management • Sensitive Data Exposure • Access Control and Password Handling • PHP Security Settings Sample• Cross-Site Scripting • Logging and Monitoring • API Protection • Cross-Site Request Forgery • ...and more. Written by PHP professional Eric Mann, this book builds on his experience in building secure, web applications with PHP.

Order Your Copy http://phpa.me/security-principles Sample