Search icon
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
The Art of Modern PHP 8

You're reading from  The Art of Modern PHP 8

Product type Book
Published in Oct 2021
Publisher Packt
ISBN-13 9781800566156
Pages 420 pages
Edition 1st Edition
Languages
Author (1):
Joseph Edmonds Joseph Edmonds
Profile icon Joseph Edmonds

Table of Contents (19) Chapters

Preface 1. Section 1 – PHP 8 OOP
2. Chapter 1: Object-Oriented PHP 3. Chapter 2: Inheritance and Composition, Encapsulation and Visibility, Interfaces and Concretions 4. Chapter 3: Advanced OOP Features 5. Section 2 – PHP Types
6. Chapter 4: Scalar, Arrays, and Special Types 7. Chapter 5: Object Types, Interfaces, and Unions 8. Chapter 6: Parameter, Property, and Return Types 9. Section 3 – Clean PHP 8 Patterns and Style
10. Chapter 7: Design Patterns and Clean Code 11. Chapter 8: Model, View, Controller (MVC) Example 12. Chapter 9: Dependency Injection Example 13. Section 4 – PHP 8 Composer Package Management (and PHP 8.1)
14. Chapter 10: Composer For Dependencies 15. Chapter 11: Creating Your Own Composer Package 16. Section 5 – Bonus Section - PHP 8.1
17. Chapter 12: The Awesomeness That Is 8.1 18. Other Books You May Enjoy

PHP OOP basics

In this section, we are going to cover a very brief overview of the basic OOP features of PHP 8. I am not aiming to be comprehensive here; if this is new to you, then I suggest you visit the official docs, which do a great job of explaining these features in detail:

PHP: Classes and Objects - Manual

https://www.php.net/manual/en/language.oop5.php

We will be covering further details throughout the book; however, the following should be enough to whet your appetite and let you know whether your knowledge is up to date. We're going to look briefly at classes, interfaces, and namespaces. This should all be quite familiar to you already and if it is not, then a little extra revision of these topics would be useful so that you can get the most out of later chapters.

Classes

The basic building block of PHP OOP is the class. As briefly mentioned earlier in this chapter, classes are the things that get instantiated in the "objects" that OOP talks about.

A simple class looks like this:

src/Part1/Chapter1/Simple/SimpleClass.php

Repo: https://git.io/JRw7C

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1\Simple;
class SimpleClass
{
    public function __construct(public string $name = 'Simon')
    {
    }
}

To create an instance of the class, we use the new keyword, which then gives us an "instance" that we can assign to a variable and generally interact with.

Then, a new instance is created; PHP will check for a method called __construct and if it exists, it will be called. The parameters passed into this method are those that are passed in when calling the class:

src/Part1/Chapter1/simple.php

Repo: https://git.io/JRw7W

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1;
use Book\Part1\Chapter1\Simple\SimpleClass;
require __DIR__ . '/../../../vendor/autoload.php';
$instance = new SimpleClass();
echo "\n" . $instance->name; // Simon
$instance2 = new SimpleClass('Sally');
echo "\n" . $instance2->name; //Sally

Output:

Inside the class, we have a variable called $this, which is available to every method inside the class and refers to the current instance. It provides access to all the methods and properties of that instance:

src/Part1/Chapter1/Simple/SimpleWithGetter.php

Repo: https://git.io/JRw7l

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1\Simple;
class SimpleWithGetter
{
    public function __construct(private string $name = 'Simon')
    {
    }
    public function getName(): string
    {
        return $this->name;
    }
}

If the parameters are defined in the constructor with a visibility keyword (private, protected, or public), then the parameter will automatically be defined as a property of the class with that visibility level.

If a visibility level is not specified, then in order to assign the parameter value to the class as a property, we have to do something like this:

src/Part1/Chapter1/Simple/SimpleManualAssignment.php

Repo: https://git.io/JRw78

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1\Simple;
class SimpleManualAssignment
{
    private string $name;
    public function __construct(string $name = 'Simon')
    {
        // take the constructor param and manually assign to class property
        $this->name = $name;
    }
}

There are three ways that properties can be set in the class:

  • In the constructor parameters
  • Defining the property in the class body
  • Dynamically assigning the property without a definition (don't do this)

Have a look at the following snippet, which demonstrates these three options:

src/Part1/Chapter1/Simple/SimplePropertyAssignment.php

Repo: https://git.io/JRw74

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1\Simple;
class SimplePropertyAssignment
{
    private string $defined = 'defaultValue';
    public function __construct(
        private string $constructorParam = 'constructorValue'
    ) {
        // this is a bad idea, dynamicProperty is untyped and public
        $this->dynamicProperty = 'dynamicallyAdded';
    }
}

When a property is declared dynamically, it can only ever be public, and it cannot be typed. This means that we lose a huge amount of safety and open the door to a whole range of bugs:

src/Part1/Chapter1/simple_properties.php

Repo: https://git.io/JRw7B

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1;
use Book\Part1\Chapter1\Simple\SimplePropertyAssignment;
require __DIR__ . '/../../../vendor/autoload.php';
$instance = new SimplePropertyAssignment();
// dynamic property is public
echo "\n" . $instance->dynamicProperty;
// dynamic property is untyped and can be anything
$instance->dynamicProperty = 123;
echo "\n" . $instance->dynamicProperty;

Output:

As you hopefully now realise, public properties are generally not something you want, apart from in very particular circumstances. If you ever see dynamically assigned properties, the general expectation is that it is a mistake, and for this reason, most integrated development environments (IDEs) will highlight it as a warning.

Interfaces

Interfaces are pieces of code that never contain any functionality, but what they do define are the… well… interface that classes must provide when they implement the specific interface.

For example:

src/Part1/Chapter1/interface.php

Repo: https://git.io/JRw7R

<?php
declare(strict_types=1);
namespace Book\Part1\Chapter1;
interface GetsSomethingInterface
{
    /**
     * This interface defines one method.
     * It must be called "getSomething" and it must return a string
     */
    public function getSomething(): string;
}
class GetsSomethingClass implements GetsSomethingInterface
{
    public function getSomething(): string
    {
        return 'something';
    }
}
echo "\n" . (new GetsSomethingClass())->getSomething();

Output:

By implementing an interface, the class tells the world that it conforms to a set of strict rules. It must implement the methods in the interface as they are defined. That allows other code to not necessarily care exactly what class it is and confidently call methods as we know they will be there, and we know what types they will return.

Read more about interfaces in the official docs:

PHP: Object Interfaces - Manual

https://www.php.net/manual/en/language.oop5.interfaces.php

Namespaces

This is not strictly part of OOP but is highly relevant, so I'm including it here. Namespaces are designed to make naming things a lot, lot simpler. Before we had namespaces, our code needed to worry about the fact that there might be a situation where some other piece of code tries to use the same name as the one you are trying to use for your class, function, or another item. This led to things having very long names, such as Mage_Catalog_Product_CompareController – all in an effort to ensure that there is no risk of a name clash, because a name clash is a fatal error.

The advent of namespaces meant that we could now define a clean slate for naming things. We need to define a unique namespace and then within that namespace, we can give things lovely, short, meaningful names with no fear of a name clash:

<?php
namespace My\Library;
class Helper {}
function write(string $value){}

There is nothing in PHP itself that defines which namespace any particular file should use; however, modern PHP developers have almost completely adopted something called PSR-4:

PSR-4: Autoloader - PHP-FIG

https://www.php-fig.org/psr/psr-4/

As you can see if you follow the link, PSR-4 lays out rules around exactly how to use namespaces and how they should correspond to the file/folder structure of your project.

What is PSR?

If you haven't heard of PSR before, it might be worth reading into it a bit. PSR stands for PHP Standards Recommendations. It is something that was put together and promoted by a group of PHP developers called the PHP Framework Interop GroupPHP-FIG for short.

What they have done is tried to put together coding standards and basic interfaces to define general components. The goal is that rather than each framework being its own weird and wonderful isolated pond, there are standard approaches to standard problems. The huge advantage of this is that tooling and libraries are less coupled to frameworks and we can have nice things that were primarily built for one framework or application being useable by the rest of the PHP ecosystem. DI containers are actually a great example of this.

This policy defines a folder structure and naming convention that corresponds a class's namespace. Each \ in the namespace name corresponds to a subdirectory in the folder structure, with a defined prefix applied within a defined base directory.

This example is copied from the PSR-4 page:

If you have been paying close attention to the code snippets, you may have spotted that the example code for this book also conforms to PSR-4. The root namespace prefix is Book\ and this corresponds to the src directory in the code repo. For code that is designed to be shared publicly, this root namespace is like a unique username or brand and is generally standardized for all packages released by the same person or company. We will explore these kinds of packages later in the book.

For any files in the base directory, the namespace is simply the namespace prefix. If the file is in a subfolder, then the namespace is extended to match the subfolder name.

If you look back through the code snippets in this chapter, you can see that as we are in Part1 and Chapter1, the code snippets are being stored in src/Part1/Chapter1, and for each code snippet that is in that folder, the namespace is defined as follows:

namespace Book\Part1\Chapter1;

Any code snippets in a subfolder have the namespace extended to match; for example, the file /src/Part1/Chapter1/Simple/SimplePropertyAssignment.php has the namespace defined as follows:

namespace Book\Part1\Chapter1\Simple;

PSR-4 is a very sane and sensible system to follow, and I highly encourage you to do so.

Read more about namespaces in the official docs:

PHP: Namespaces - Manual

https://www.php.net/manual/en/language.namespaces.php

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}