Advanced OOP and Design Patterns
Advanced OOP and Design Patterns
and Design Patterns
Stefan Priebsch
thePHP.cc
CodeWorks 09
SQL
</head>
<?php $query = "select `postId`,`filename`,`filesize`,`imgId` from
`tiki_blog_posts_images` where `postId`=?";
$result = $this->query($query,array((int) $postId));
$ret = array();
while ($res = $result->fetchRow()) {
$imgId = $res['imgId'];
$res['link'] = "<img src='tiki-view_blog_post_image.php?
imgId=$imgId' border='0' alt='image' />";
$parts = parse_url($_SERVER['REQUEST_URI']);
$path = str_replace('tiki-blog_post.php', 'tiki-
view_blog_post_image.php', $parts['path']);
$res['absolute'] = $tikilib->httpPrefix(). $path . "?
imgId=$imgId";
$ret[] = $res;
} return $ret; } ?>
<?php if ($GLOBALS['text_dir'] === 'ltr') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<frame frameborder="0" id="frame_content" src="<?php echo
HTML
$main_target; ?>" name="frame_content" />
<?php if ($GLOBALS['text_dir'] === 'rtl') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<noframes><body><p><?php echo $GLOBALS['strNoFrames']; ?></p>
</body></noframes></frameset></html>
<?php header('Content-Type: text/html; charset=' .
$GLOBALS['charset']); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="<?php echo $lang_iso_code; ?>"
PHP
lang="<?php echo $lang_iso_code; ?>"
dir="<?php echo $GLOBALS['text_dir']; ?>">
<head>
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
<title>phpMyAdmin <?php echo PMA_VERSION; ?> -
<?php echo htmlspecialchars($HTTP_HOST); ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php
echo $GLOBALS['charset']; ?>" />
<meta name="robots" content="noindex,nofollow" />
<script type="text/javascript">
window.onload = function() {
if (onloadCnt == 0) { if (typeof(onLoadHandler) == "function") {
onLoadHandler();
} };</script>
<script src="./js/common.js" type="text/javascript"></script>
SQL
</head>
<?php $query = "select `postId`,`filename`,`filesize`,`imgId` from
`tiki_blog_posts_images` where `postId`=?";
$result = $this->query($query,array((int) $postId));
$ret = array();
while ($res = $result->fetchRow()) {
$imgId = $res['imgId'];
$res['link'] = "<img src='tiki-view_blog_post_image.php?
imgId=$imgId' border='0' alt='image' />";
$parts = parse_url($_SERVER['REQUEST_URI']);
$path = str_replace('tiki-blog_post.php', 'tiki-
view_blog_post_image.php', $parts['path']);
$res['absolute'] = $tikilib->httpPrefix(). $path . "?
imgId=$imgId";
$ret[] = $res;
} return $ret; } ?>
<?php if ($GLOBALS['text_dir'] === 'ltr') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<frame frameborder="0" id="frame_content" src="<?php echo
HTML
$main_target; ?>" name="frame_content" />
<?php if ($GLOBALS['text_dir'] === 'rtl') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<noframes><body><p><?php echo $GLOBALS['strNoFrames']; ?></p>
</body></noframes></frameset></html>
<?php header('Content-Type: text/html; charset=' .
$GLOBALS['charset']); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="<?php echo $lang_iso_code; ?>"
PHP
lang="<?php echo $lang_iso_code; ?>"
dir="<?php echo $GLOBALS['text_dir']; ?>">
<head>
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
<title>phpMyAdmin <?php echo PMA_VERSION; ?> -
<?php echo htmlspecialchars($HTTP_HOST); ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php
echo $GLOBALS['charset']; ?>" />
<meta name="robots" content="noindex,nofollow" />
<script type="text/javascript">
window.onload = function() {
if (onloadCnt == 0) { if (typeof(onLoadHandler) == "function") {
onLoadHandler();
} };</script>
<script src="./js/common.js" type="text/javascript"></script>
SQL
</head>
<?php $query = "select `postId`,`filename`,`filesize`,`imgId` from
`tiki_blog_posts_images` where `postId`=?";
$result = $this->query($query,array((int) $postId));
$ret = array();
while ($res = $result->fetchRow()) {
$imgId = $res['imgId'];
$res['link'] = "<img src='tiki-view_blog_post_image.php?
imgId=$imgId' border='0' alt='image' />";
$parts = parse_url($_SERVER['REQUEST_URI']);
$path = str_replace('tiki-blog_post.php', 'tiki-
view_blog_post_image.php', $parts['path']);
$res['absolute'] = $tikilib->httpPrefix(). $path . "?
imgId=$imgId";
$ret[] = $res;
} return $ret; } ?>
<?php if ($GLOBALS['text_dir'] === 'ltr') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<frame frameborder="0" id="frame_content" src="<?php echo
HTML
$main_target; ?>" name="frame_content" />
<?php if ($GLOBALS['text_dir'] === 'rtl') { ?>
<frame frameborder="0" id="frame_navigation" src="navigation.php<?
php echo $url_query; ?>" name="frame_navigation" /><?php } ?>
<noframes><body><p><?php echo $GLOBALS['strNoFrames']; ?></p>
</body></noframes></frameset></html>
PHP
SQL
HTML
Presentation
Logic
Data Access
Separation of
Concerns
Good OOP starts
before classes
come into play
Do we
need OOP?
IF-GOTO programs
LOOP programs
WHILE programs
IF-GOTO and
WHILE programs
are equally powerful.
Every WHILE program
can be simulated by a
WHILE program with
only one while loop.
OOP is
syntactical sugar
Then Why OOP?
Readability
class BlogPosting
{
public function addComment(Comment $comment)
}
class BlogPosting
{
public function addComment(Comment $comment)
{
$this->comments[] = $comment;
}
}
class BlogPosting
{
public function addComment(Comment $comment)
{
$this->comments[] = $comment;
if ($comment->getAuthor()->isRegistered()) {
$comment->setApproved(true);
}
}
}
Encapsulation
Keeping Secrets
Interface
and
Implementation
$email->send();
$pdf->generate();
Maintainability
>150x
Relative Cost of a Bugfix
50x
20x
10x
1x 5x
Req Design Code DevT AccT Ops
Source: Barry Boehm: „EQUITY Keynote Address“, March 19th, 2007
Extensibility
class Customer
{
protected $discount = 0;
return parent::getDiscount();
}
}
class PremiumCustomer extends Customer
{
protected $discount = 5;
return 10;
}
return parent::getDiscount();
}
...
}
class PremiumCustomer extends Customer
{
...
...
}
class PremiumCustomer extends Customer
{
protected $specialDiscount= 10;
return $this->specialDiscount;
}
return parent::getDiscount();
}
}
class MostValuedCustomer extends PremiumCustomer
{
protected $discount = 10;
protected $specialDiscount= 20;
}
Reusability
Only isolated and
loosely coupled
classes are reusable.
Maintainability
Is OOP slow?
foo() 3.09 µsec
Test::foo() 3.26 µsec
$test->foo() 3.12 µsec
class Something
{
public function loadData()
{
$this->data = file_get_contents(BASEPATH . '/file.ext');
}
}
...
$something = new Something();
$something->loadData();
class Something
{
protected $basePath = BASEPATH;
$this->dbAdapter = $dbAdapter;
}
...
}
class Something
{
protected $logger;
...
}
class DbGateway
{
protected $isConnected = false;
...
...
}
class DatabaseLogger extends Logger extends DbGateway
{
...
}
Multiple
Inheritance
?
class Something
{
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
// perform calculations
…
// sort output
...
}
}
class Something
{
public function run()
{
$this->initialize();
$this->calculateStuff();
$this->doLogging();
$this->sortOutput();
}
}
Template Method
class Something
{
abstract protected function initialize();
abstract protected function calculateStuff();
abstract protected function doLogging();
abstract protected function sortOutput();
-- Christopher Alexander
A design pattern
is a general reusable
solution to a commonly
occurring problem.
A design pattern is not a
finished design that can be
transformed directly into code.
Architectural
Patterns
Design
Patterns
Idioms
Problem: display
a progress bar
class Something
{
protected function performCalculation()
{
...
foreach ($items as $item) {
… process the item …
print '.';
}
...
}
}
Subject/Observer
The subject maintains a list of
observers and notifies them on
status changes.
interface SplSubject
{
public function attach(SplObserver $observer);
public function detach(SplObserver $observer);
...
}
class Subject implements SplSubject
{
…
...
}
class Subject implements SplSubject
{
...
if ($item->isDir()) {
print '[' . $item->getPathname() . '] ';
}
if ($item->isFile()) {
print '.';
}
}
}
$progressBar = new ProgressBar();
$something->doWork();
Factory
Defines an interface for creating
a family of objects. The concrete
classes that are to be instantiated
are not clearly defined.
Creates objects for you.
abstract class Plane
{
static public function getInstance($type)
{
return new $type;
}
}
class Boeing extends Plane
{
}
$b = Plane::getInstance('AirbusA340');
abstract class Plane
{
static public function getInstance($type)
{
switch ($type) {
case 'Boeing777':
return new Boeing777();
…
default:
throw new RuntimeException('...');
}
}
}
abstract class Plane
{
static public function getInstance($type)
{
if (!in_array($type, array('Boeing777', 'AirbusA340', …)))
{
throw new RuntimeException('...');
}
$classname = $this->classMap[$type];
return new $classname;
}
}
Singleton
Limits number of instances
of a class to one object.
Limits number of instances
of a class to one object.
class Singleton
{
static protected $instance;
return self::$instance;
}
}
class Singleton
{
static protected $instance;
return self::$instance;
}
}
class Something
{
public function doWork()
{
$singleton = Singleton::getInstance();
$singleton->...
...
}
}
class Something
{
public function doWork($reference)
{
$reference->...
...
}
}
Registry
A well-known object used
by others to find shared
objects and services.
…
$db = StaticRegistry::getDbAdapter();
...
class StaticRegistry
{
static protected $dbAdapter;
return self::$dbAdapter;
}
}
…
$db = Registry::getInstance()->getDbAdapter();
...
class SingletonRegistry
{
static protected $instance;
protected $dbAdapter;
return $this->dbAdapter;
}
}
class Registry
{
…
return $this->dbAdapter;
}
}
MVC
Classical
MVC
Model
Represents
domain-specific data
View
Renders
model data
Controller
Handles events
and modifies model
Presentation V
Logic C
Data Access M
Model != Data Access
Model != Data Access
Controller
View Model
Controller observes View
Controller
View Model
Controller fetches data from View
Controller
View Model
Controller modifies Model
Controller
View Model
View observes Model
Controller
View Model
View fetches data from Model
Controller
View Model
MVC
on the Web
Client V
Server C M
View is
remote
Controller
View Model
Controller can't observe View
Controller
View Model
View can't observe Model
Controller
View Model
View doesn't talk to Controller
Front
Controller
Controller
View Model
Front
Controller
Controller
HTTP
Request
View Model
Front execute()
Controller
Controller
HTTP
Request
View Model
Front execute()
Controller
Controller
HTTP
Request
View Model
getData()
Front execute()
Controller
Controller
HTTP ()
ata
Request
etD
s
View Model
getData()
Controller
selects View
View generates
full HTML page
Workflows by
Controller chaining
Lean Controller,
Fat Model
No data access
in Controller or Model
No presentation
in Controller or Model
Separation of
Concerns
Golden Rules
„Hang the rules.
They're more like
guidelines anyway.“
--Elizabeth Swann,
Pirates of the Caribbean
Make
dependencies
explicit.
„Life can only be
understood backwards,
backwards,
but it must be lived
forwards.“
forwards.“
-- Soren Kierkegaard
Solve your
problem.
Do one thing
at a time.
Let others
do the work.
Do not care
about others.
Keep it
simple.
„Debugging is twice as hard
as writing the code in the
first place. Therefore, if you
write the code as cleverly as
possible, you are, by definition,
not smart enough
to debug it.“
-- Brian W. Kernighan
Do not
comment.
Do not
comment. *
*
Some restrictions apply.
”The most important
single aspect of software
development ...
… is to be clear about
what you are trying to
build.”
-- Bjarne Stroustrup
Name the thing.
„There's no sense being
exact about something
if you don't even know
what you're talking about.“
-- John von Neumann
It has to fit
on one page.
”Measuring programming
progress by lines of code
is like measuring aircraft
building progress by weight.”
weight.”
-- Bill Gates
Accept Change.
”I may not have gone
where I intended to go,
but I think I have ended
up where I needed to be.“
-- Douglas Adams
Thank you.