Skip to main content
Object Features
1. Access Control
2. Managing Types
3. Namespacing and Autoloading
4. Exceptions
PART 1: Access Control
Scope
Visibility: Public, Private, Protected
State: Static, Final
Magic
Personal Scope
Acquaintance (Social)
Friends
Professional
Family
Romantic
“MOM!”
“MOM!”
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
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

}

}
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
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";

}

...

}
Accessing Child Visibility
$developer = new Developer();

echo $developer->name;//child $name

$developer->name = "tiberias";//child $name

echo $developer->name;//child $name

echo $developer->getName();//parent $name

//ProgrammertiberiasGuest
echo $developer->getSalutation();//child $greeting, parent $name

//Hello Guest, Developer
$developer->setName("alena");//parent $name

echo $developer->name;//child $name

echo $developer->getName();//parent $name

//tiberiasAlena
echo $developer->getSalutation();//child $greeting, parent $name

//Hello Alena, Developer
QUESTIONS
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
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];

}

}
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];

}

}
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!
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
QUESTIONS
Magic
Magic Methods
Magic Constants
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
Magic Constants
Predefined constants in PHP
For more see http://php.net/manual/en/
language.constants.predefined.php
Using Magic Methods and Constants
class User {
...



public function __construct($name) {

$this->setName($name);

}



public function __toString() {

return __CLASS__. “: “

. $this->getSalutation();

}

...

}
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
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 

}

}

}
QUESTIONS
PART 2: Managing Types
Type Declarations (Hints)
Return Types
Type Juggling
Strict Types
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;

}

}
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;

}

}
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"
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"
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
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
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
QUESTIONS
PART 3: Namespacing
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 ‘’
Namespace: Directory
classes
Developer.php
sketching
oop
SettersTrait.php
User.php
UserInterface.php
index.php
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 {…}
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();
QUESTIONS
PART 4: Autoloading
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();
PART 5: Exceptions
Exception Hierarchy
Exception implements Throwable
…
Error implements Throwable
TypeError extends Error
ParseError extends Error
ArithmeticError extends Error
DivisionByZeroError extends ArithmeticError
AssertionError extends Error
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

}
Custom Exception Handler
function exception_handler($e)
{
echo "Uncaught exception: ", $e->getMessage(), "n";
}
set_exception_handler('exception_handler');
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");
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
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