<style> .markdown-body h1:first-of-type { margin-top: 24px; } .markdown-body h1 { margin-top: 64px; } .markdown-body h1 + h2 { margin-top: 32px; } .markdown-body h2 { margin-top: 48px; } .markdown-body h3 { color: cornflowerblue; } .exercise { font-size: 150%; font-weight: bold; color: rgb(227,112,183); } .note { color: red; font-weight: bold; } #mq { padding: 20px; background-color: red; } @media screen and (width >= 500px) { #mq { background-color: green; color: white; } } </style> # COMP 4515 Lesson 5 ## Object-Oriented PHP PHP supports many common features of Object-Oriented Programming: Inheritance, Interfaces, Visibility Modifiers, and more. As of PHP 7, the syntax for creating classes, methods, and properties is very similar to languages like Java and C#. To create a class in PHP, we use the `class` keyword ```php class Student { } ``` The __construct method is used to declare a constructor, which is automatically called when a new object is created from the class. ```php class Student { function __construct() { } } ``` Any arguments passed to the constructor must, as with all variables in PHP, be prefaced with a '$'. Object properties (and methods) can be declared using any of the available visibility scopes: public, protected, or private. If a visibility scope is not specified, the default is public. ```php class Student { private $student_id; // public by default function __construct($student_id) { } public function get_student_id() { } } ``` When referencing object properties and/or methods, we use the object operator, `->` , and from within a class we can refer to properties and methods using `$this`. Note in the example below how the `$student_id` variable name changes when used in combination with `$this` ```php class Student { private $student_id; public function __construct($student_id) { $this->student_id = $student_id; } public function get_student_id() { return $this->student_id; } } ``` Objects are created from a class using the `new` operator, and once an object is created we can use the object operator to access its properties and methods. ```php $student1 = new Student('A01234567'); echo $student->get_student_id(); ``` ### Strict Typing in Classes PHP allows us, as of PHP 7.4, to declare types for class properties, and will generate errors if an attempt to set an incorrect type is made. ```php class Student { private string $student_id; // ? before the type specifies that it can be null OR the declared type private ?string $email; } ``` We can also specify the type of function parameters and return values. ```php class Student { // update_email accepts a single string argument, and returns a string public function update_email(string $new_email): string { $this->email = $new_email; return $this->email; } } ``` ### Static Methods and Properties PHP supports static methods and properties – methods and properties that can be accessed from a class without having to create an object. Static properties are often used for values that should not change over the life of a program's execution, for example a database connection. ```php class Connector { private static $db_connection; public static create_connection($host, $db, $user, $pass) { } } ```   To access static data from within a static method, we can use the class name followed by `::` , the 'scope resolution operator'. ```php class Connector { private static $db_connection; public static create_connection($host, $db, $user, $pass) { Connector::$db_connection = new PDO(); } } ```   The scope resolution operator can also be used outside the class to access static methods or (public) static properties. ```php $conn = Connector::create_connection('', '', '', ''); ``` ### Inheritance PHP supports (single) inheritance via the extends keyword, and as with other programming languages, the subclass inherits any public or protected properties and methods. ```php class Student { private string $student_id; private string $email; public function update_email(string $new_email): string { $this->email = $new_email; return $this->email; } } class FourthTermStudent extends Student { private DateTime $convocation_date; // Inherits student_id, email, and update_email from Student // Overriden methods must have the same function signature // as the parent method public function update_email(string $new_email): string { } } ```   If a child class needs to access a property or method from its inherited class, the `parent` keyword can be used with the scope resolution operator. `parent` can also be used to call the parent constructor, as in `parent::__construct()` ```php class Student { private string $student_id; private string $email; public function update_email(string $new_email): string { $this->email = $new_email; } } class FourthTermStudent extends Student { private DateTime $convocation_date; public function update_email(string $new_email): string { // perform additional checks, e.g. convocation date not passed? parent::update_email($new_email); } } ``` ### Namespaces and aliasing class names with 'use' To keep our code encapsulated, or for any cases where two or more functions, constants, or classes have the same name, PHP provides namespaces as a way to help differentiate and/or locate a particular instance of that function, constant, or class. Namespaces are analogous to folder names, and can be mapped directly via nested namespaces. Imagine the following file/folder structure for an MVC (Model/View/Controller) app containing several class files: ``` [App (root folder)]     |     Controller.php --- [Models] --------------- [Views]                         |                       |                         User.php                 Home.php                                                   Profile.php ```   We might choose to use 'App' as our root namespace, which would be declared inside Controller.php as follows: ```php namespace App; class Controller { } ```   Any file requiring this controller would then need to refer to this class by its namespaced name, using back-slash syntax. ```php require_once('App/Controller.php'); $controller = new App\Controller(); ``` Likewise, for any classes in subfolders we could use the folder name as a nested namespace: _User.php_ ```php namespace App\Models; class User { } ``` _Home.php_ ```php namespace App\Views; class Home { } ``` and those classes would also need to be referenced by their full namespace: ```php require_once('App/Controller.php'); require_once('App/Models/User.php'); require_once('App/Views/Home.php'); $controller = new App\Controller(); $user = new App\Models\User(); $view = new App\Views\Home(); ``` This helps to ensure that we do not have naming collisions between, for example, two classes named User.php, but it does result in longer, less readable usage of those classes. To alleviate this, PHP also provides the `use` keyword, which allows use to alias a class to a new, shorter name. With the use of `use`, we can transform the above code to: ```php require_once('App/Controller.php'); require_once('App/Models/User.php'); require_once('App/Views/Home.php'); use App\Controller as Controller; use App\Models\User as User; use App\Views\Home as Home; $controller = new Controller(); $user = new User(); $view = new Home(); ``` This helps us to keep our code isolated and well-organized, but it has one downside: PHP will attempt to resolve any classes residing outside our namespace (including built-in classes) to classes inside our namespace. To demonstrate, imagine that you want to create a PDO instance to interact with a database inside the Controller.php class above. ```php namespace App; class Controller { private $conn; public function __construct($connstring) { $this->conn = new PDO(...); // fails! } } ``` The above line,` $this->conn = new PDO()` will fail because PHP, by default, looks for a class named PDO _inside our namespace_ (i.e. App\PDO), which does not exist. So we must explicitly tell PHP that the class in question, PDO, is not inside our namespace. To accomplish this, we simply have to preface the class name with a slash: ```php namespace App; class Controller { private $conn; public function __construct($connstring) { $this->conn = new \PDO(...); // works! } } ``` For more information on OOP in PHP, [consult the manual](https://www.php.net/manual/en/oop5.intro.php)