Get a quick refresher on all aspects of Objects, as we cover basic inheritance and method/property visibility. We’ll learn these by example. We’ll see magic methods and anonymous functions. We’ll also learn about Exceptions and error handling the PHP way.
6. Visibility
Controls who can access what. Restricting access to some of the
object’s components (properties and methods), preventing unauthorized
access.
Public - everyone
Protected - inherited classes
Private - class itself, not children
Children can be more restrictive but NOT less restrictive
7. class User {
public $lang = "en"; //public
private $name = “Guest"; //private
protected $greeting = [ ‘en’ => “Welcome”, ‘sp’ => “Hola” ]; //protected
public function getSalutation($lang = null) { //polymorphic method
$lang = $this->getLang($lang); //abstracting
return $this->greeting[$lang] . " " . $this->name;
}
protected function getLanguage($lang) { //reuse
if (!array_key_exists($lang, $this->greeting)) $lang = $this->lang;
return $lang;
}
public function setName($name) { //setter
$this->name = ucwords($name); //control formatting
}
public function getName() { //getter
return $this->name; //can access private
}
}
8. Accessing Visibility
$guest = new User();
echo $guest->getSalutation();
//$guest->name = "alena"; //private not accessible
$guest->setName("alena");
//$guest->greeting = "Hello";//protected not accessible
echo $guest->getSalutation(‘sp’);
echo "Hello " . $guest->getName();
When the script is run, it will return:
Welcome GuestHola AlenaHello Alena
9. Accessed by a child class
class Developer extends User {
public $name = "Programmer";//new property
protected $greeting = "Hello";//overridable, not private
//override method
public function getSalutation($lang = null) {//same params
return $this->greeting //protected child string
." ".$this->getName() //private parent
.", Developer";
}
...
}
12. State
Static
Do not need to instantiate an object
Static methods must be public
Internal Access: self::, parent::, static::
Late static bindings: class that’s calling
Final
Methods cannot be overridden
Class cannot be extended
13. class User {
...
protected static $encouragements = array(
"You are beautiful!",
"You have this!"
);
final public static function encourage() {
//Late Static Bindings, class that’s calling
$int = rand(1, count(static::$encouragements));
return static::$encouragements[$int-1];
}
}
14. final class Developer extends User {
...
private static $encouragements = array(
"You are not your code",
"There has never been perfect software"
);
public static function encourage() {
//error parent was final
}
public static function devEncourage() {
$int = rand(1, count(self::$encouragements));
return self::$encouragements[$int-1];
}
public static function userEncourage() {
$int = rand(1, count(parent::$encouragements));
return parent::$encouragements[$int-1];
}
}
15. Calling State
//echo User::$encouragements[0];//Error protected
echo Developer::$encouragements[0];
echo User::encourage();//User (static::)
echo Developer::encourage();//Developer (static::)
echo Developer::devEncourage();//Developer (self::)
echo Developer::userEncourage();//User (parent::)
class Architect extends Developer {
//Error: Developer is final
}
When the script is run, it will return:
You are beautiful!You are beautiful!You are not your code!There has never been perfect
software.You have this!
16. class Developer extends User {
...
//must match array type of parent
protected $greeting = [ ‘en’ => “Hello”, ‘sp’ => “Hola” ];
public function getSalutation($lang = ‘en’) { //extended
$salutation = parent::getSaluation($lang); //not a static call
return $salutation . ", Developer";
}
}
$developer = new Developer();
$developer->setName("alena");
echo $developer->getSalutation();
When the script is run, it will return:
Hello Alena, Developer
19. Magic Methods
Setup just like any other method
The Magic comes from the fact that they are
triggered and not called
For more see http://php.net/manual/en/
language.oop5.magic.php
21. Using Magic Methods and Constants
class User {
...
public function __construct($name) {
$this->setName($name);
}
public function __toString() {
return __CLASS__. “: “
. $this->getSalutation();
}
...
}
22. Invoking the Magic
$alena = new User("alena");
echo $alena;
$tiberias = new Developer("tiberias");
echo $tiberias;
When the script is run, it will return:
User: Welcome Alena
Developer: Welcome Tiberias, Developer
23. Magic Setter Trait
trait SettersTrait {
public function __set($name, $value) { //magic method
$setter = 'set'.$name; //creating method name
if (method_exists($this, $setter)) {
$this->$setter($value); //variable function or method
//$this->{‘set’.$name}; //optionally use curly braces
} else {
$this->$name = $value; //variable variable or property
}
}
}
25. PART 2: Managing Types
Type Declarations (Hints)
Return Types
Type Juggling
Strict Types
26. class User {
…
public function getSalutation(string $lang = null) { //accept string, null or nothing
$lang = $this->getLang($lang);
return $this->greeting[$lang] . " " . $this->name;
}
public function getLanguage(?string $lang) { //accept string or null
if (!array_key_exists($lang, $this->greeting)) $lang = $this->lang;
return $lang;
}
public function setName(string $name) { //accept string only
$this->name = ucwords($name);
}
public function setName(string $name) {//accept string only
$this->name = ucwords($name);
}
public function getName() {
return $this->name;
}
public function setGreeting(array $greeting){ //accept array only
$this->greeting = $greeting;
}
}
27. class User {
…
public function getSalutation(string $lang = null): string { //return string
$lang = $this->getLang($lang);
return $this->greeting[$lang] . " " . $this->name;
}
public function getLanguage(?string $lang): ?string { //return string or null
if (!array_key_exists($lang, $this->greeting)) $lang = $this->lang;
return $lang;
}
public function setName(string $name): void { //no return
$this->name = ucwords($name);
return; //this is void as well
}
public function setName(string $name): void {//no return
$this->name = ucwords($name);
}
public function getName(): string {
return $this->name;
}
public function setGreeting(array $greeting): void { //no return
$this->greeting = $greeting;
}
}
28. Type Juggling
//By default, scalar type-declarations are non-strict
class User {
…
public function setName(string $name): void { //will attempt to convert to string
$this->name = ucwords($name);
}
}
$guest = new User(1);
var_dump($guest->getName());
// string(1) "1"
29. Type Juggling
//By default, scalar type-declarations are non-strict
class User {
…
public function getName(): string {
return 2; // will convert to return string
}
}
$guest = new User(1);
var_dump($guest->getName());
// string(1) “2"
30. Type Juggling
//By default, scalar type-declarations are non-strict
class User {
…
public function setGreeting(array $greeting): void { //getter
$this->greeting = $greeting; //can access private
}
}
$guest = new User(1);
$guest->setGreeting("Greetings");
// TypeError: Argument 1 passed to User::setGreeting() must be of the type array, string given
31. Strict Types
declare(strict_types=1);
class User {
…
public function setName(string $name): void { //MUST pass string
$this->name = ucwords($name);
}
}
$guest = new User(1);
//TypeError: Argument 1 passed to User::setName() must be of the type string, integer
given
32. Strict Types
declare(strict_types=1);
class User {
…
public function getName(): string { //MUST return type string
return 2; //attempt int
}
}
$guest = new User();
$guest->getName();
//TypeError: Return value of User::getName() must be of the type string, integer returned
36. Namespacing
SHOULD Separate files for each class, interface, and trait
Add to the top of each file
namespace sketchingsoop;
When calling a class file link to full path or ‘use’ path
Default namespace is current namespace
No namespace is global namespace ‘’
38. Setting Namespaces
//classes/sketchings/oop/User.php: namespace referencing same namespace
namespace sketchingsoop;
class User implements UserInterface {…}
//classes/Developer.php: OPTION 1 use path
use sketchingsoopUser;
class Developer extends User {…}
//classes/Developer.php: OPTION 2 full path
class Developer extends sketchingsoopUser {…}
39. Using Namespaces: index.php
<?php
require_once 'classes/sketchings/oop/SettersTrait.php';
require_once 'classes/sketchings/oop/UserInterface.php';
require_once 'classes/sketchings/oop/User.php';
require_once ‘classes/Developer.php';
//Order is critical
$guest = new Developer(); //global namespace
echo $guest->getSalutation();
42. Autoloading: index.php
<?php
// Add your class directory to include path
set_include_path('classes/');
// Use default autoload implementation
spl_autoload_register();
$guest = new Developer(); //global namespace
echo $guest->getSalutation();
45. Catching Exceptions
try {
// Code that may throw an Exception or Error.
} catch (DivisionByZeroError $e) {
// Executed only in PHP 7 for DivisionByZeroError
} catch (Throwable $e) {
// Executed only in PHP 7, will not match in PHP 5
} catch (Exception $e) {
// Executed only in PHP 5, will not be reached in PHP 7
}
47. Error to Exception
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message);//$message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
48. Resources
Mastering Object-Oriented PHP by Brandon Savage
LeanPub: The Essentials of Object Oriented PHP
Head First Object-Oriented Analysis and Design
PHP the Right Way
49. Alena Holligan
• Wife, and Mother of 3 young children
• PHP Teacher at Treehouse
• Portland PHP User Group Leader
• Cascadia PHP Conference (cascadiaphp.com)
@alenaholligan alena@holligan.us https://joind.in/talk/8b9ca