Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
100% found this document useful (3 votes)
3K views

Advanced OOP and Design Patterns

Stefan Priebsch's slides from Codeworks 2009

Uploaded by

kaplumb_aga
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
3K views

Advanced OOP and Design Patterns

Stefan Priebsch's slides from Codeworks 2009

Uploaded by

kaplumb_aga
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 229

Advanced OOP

and Design Patterns
Stefan Priebsch
thePHP.cc
CodeWorks 09

Copyright © 2009 thePHP.cc, Germany


Premium PHP Consulting & Training. Worldwide.

Sebastian Arne Stefan


Bergmann Blankerts Priebsch
Why OOP?
<?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 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;

public function getDiscount()


{
return $this->discount;
}
}
class PremiumCustomer extends Customer
{
protected $discount = 5;
}
class PremiumCustomer extends Customer
{
protected $discount = 5;

public function getDiscount()


{
if ($this->signupYear < 2003) {
return 10;
}

if ($this->getTotalRevenue() > 100000) {


return 10;
}

return parent::getDiscount();
}
}
class PremiumCustomer extends Customer
{
protected $discount = 5;

public function getDiscount()


{
if ($this->fulfilsYearCriterion() ||
$this->fulfilsRevenueCriterion()) {

return 10;
}

return parent::getDiscount();
}

...
}
class PremiumCustomer extends Customer
{
...

protected function fulfilsYearCriterion()


{
return $this->signupYear < 2003;
}

protected function fulfilsRevenueCriterion()


{
return $this->getTotalRevenue() > 100000;
}

...
}
class PremiumCustomer extends Customer
{
protected $specialDiscount= 10;

public function getDiscount()


{
if ($this->fulfilsYearCriterion() ||
$this->fulfilsRevenueCriterion()) {

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

$test = new Test();


$test->foo() 4.03 µsec

Benchmark results are different on every system.


25% slower!
1 µsec
print ~ 10 µsec
file_get_contents() ~ 30 µsec
mysql_connect() ~ 100 µsec
HTTP GET Request ~ 35,000 µsec

Benchmark results are different on every system.


I/O is where
the action is.
OOP is fast
enough.
Dealing with
Dependencies
Decoupling
Dependencies
on Constants
define('BASEPATH', '/some/absolute/path');
...

class Something
{
public function loadData()
{
$this->data = file_get_contents(BASEPATH . '/file.ext');
}
}

...
$something = new Something();
$something->loadData();
class Something
{
protected $basePath = BASEPATH;

public function loadData()


{
$this->data = file_get_contents($this->basePath . '/file.ext');
}
}
class Something
{
protected $basePath = BASEPATH;

public function setBasePath($basePath)


{
$this->basePath = $basePath;
}

public function loadData()


{
$this->data = file_get_contents($this->basePath . '/file.ext');
}
}
$something = new Something();
$something->setBasePath(BASEPATH);
$something->loadData();
class Something
{
protected $basePath;

public function setBasePath($basePath)


{
$this->basePath = $basePath;
}

public function loadData()


{
$this->data = file_get_contents($this->basePath . '/file.ext');
}
}
class Something
{
protected $basePath;

public function setBasePath($basePath)


{
$this->basePath = $basePath;
}

public function loadData()


{
if (is_null($this->basePath)) {
throw new RuntimeException('No basepath set');
}

$this->data = file_get_contents($this->basePath . '/file.ext');


}
}
class Something
{
protected $basePath;

public function __construct($basePath)


{
$this->basePath = $basePath;
}

public function loadData()


{
if (is_null($this->basePath)) {
throw new RuntimeException('No basepath set');
}

$this->data = file_get_contents($this->basePath . '/file.ext');


}
}
Files are also a
dependency
class Something
{
public function __construct($data)
{
$this->data = $data;
}
}
Dependencies on
Global Variables
class Something
{
public function loadData()
{
global $dsn;

… load data from database ...


}
}
class Something
{
public function loadData($dsn)
{
… load data from database ...
}
}
class Something
{
protected $dsn;

public function __construct($dsn)


{
$this->dsn = $dsn;
}

public function loadData()


{
… load data from database ...
}
}
class Something
{
protected $dbAdapter;

public function __construct(DatabaseAdapter $dbAdapter)


{
$this->dbAdapter = $dbAdapter;
}
}
Dependency
Injection
class Something
{
protected $dbAdapter;

public function __construct(DatabaseAdapter $dbAdapter)


{
$this->dbAdapter = $dbAdapter;
}

public function loadData()


{
… ask somebody else to load data from database ...
}
}
Delegation
Let others
do the work.
class DatabaseAdapter
{
protected $dsn;

public function __construct($dsn)


{
$this->dsn = $dsn;
}
}
$dbAdapter = new DatabaseAdapter();

$something = new Something($dbAdapter);


$something->doWork();
class DummyDatabaseAdapter extends DatabaseAdapter
{
}

$dbAdapter = new DummyDatabaseAdapter();

$something = new Something($dbAdapter);


$something->doWork();
class Something
{
protected $dbAdapter;

public function __construct(DatabaseAdapter $dbAdapter = null)


{
if (is_null($dbAdapter)) {
$dbAdapter = new DefaultDatabaseAdapter();
}

$this->dbAdapter = $dbAdapter;
}

public function loadData()


{
… load data from database ...
}
}
Dependencies
on Functions
class Something
{
public function doWork()
{
...
global_function(...);
...
}
}
require_once 'global_function.php';

$something = new Something();


$something->doWork();
require_once 'mock_global_function.php';

$something = new Something();


$something->doWork();
Dependencies
on Static Calls
class Something
{
public function loadData()
{
$dsn = Configuration::getDsn();

… load data from database ...


}
}
class Something
{
protected $configurationClass = 'Configuration';

public function setConfigurationClass($classname)


{
$this->configurationClass = $classname
}

public function loadData()


{
$classname = $this->configurationClass;
$db = $classname::getDsn();

… load data from database ...


}
}
?
class Something
{
protected $configurationClass = 'Configuration';

public function setConfigurationClass($classname)


{
$this->configurationClass = $classname
}

public function loadData()


{
$classname = $this->configurationClass;
$db = $classname::getDsn();

… load data from database ...


}
}
Will $classname
actually be a class?
class Something
{
protected $configurationClass = 'Configuration';

public function setConfigurationClass($classname)


{
$this->configurationClass = $classname
}

public function loadData()


{
$classname = $this->configurationClass;
$db = $classname::getDsn();

… load data from database ...


}
}
Will the class have
a getDsn() method?
Better let PHP
enforce this.
Dependencies
on Objects
class Something
{
public function doWork()
{
...
$this->log('…');
...
}
}
class Something
{
protected function log($message)
{
file_put_contents(LOGFILE, $message, FILE_APPEND);
}

public function doWork()


{
...
$this->log('…');
...
}
}
class Logger
{
public function log($message)
{
file_put_contents(LOGFILE, $message, FILE_APPEND);
}
}
class Something
{
protected $logger;

public function __construct()


{
$this->logger = new Logger();
}

...
}
class Something
{
protected $logger;

public function __construct()


{
$this->logger = new Logger();
}

public function doWork()


{

$this->logger->log(...);
...
}
}
class Something
{
protected $logger;

public function __construct(Logger $logger)


{
$this->logger = $logger;
}

public function doWork()


{

$this->logger->log(...);
...
}
}
class Logger
{
public function log($message)
{
file_put_contents(LOGFILE, $message, FILE_APPEND);
}
}
class Logger
{
protected $file;

public function __construct($file)


{
$this->file = $file;
}

public function log($message)


{
...
file_put_contents($this->file, $message, FILE_APPEND);
...
}
}
class DatabaseLogger extends Logger
{
protected $dsn;

public function __construct($dsn)


{
$this->dsn = $dsn;
}

public function log($message)


{
… log $message to database $dsn ...
}
}
class DbGateway
{
protected $dsn;

public function __construct($dsn)


{
$this->dsn = $dsn;
}

...
}
class DbGateway
{
protected $isConnected = false;

...

protected function connect()


{
… connect to $dsn ...
}

public function query($query)


{
if (!$this->isConnected) {
$this->connect();
}

… run $query ...


}

...
}
class DatabaseLogger extends Logger extends DbGateway
{
...
}
Multiple
Inheritance
?
class Something
{
public function __construct(Logger $logger)
{
$this->logger = $logger;
}

public function doWork()


{
...
$this->logger->log(...);
...
}
}
Do we really need to
extend Logger?
class FileLogger
{
protected $file;

public function __construct($file)


{
$this->file = $file;
}

public function log($message)


{
...
file_put_contents($this->file, $message, FILE_APPEND);
...
}
}
class DatabaseLogger extends DbGateway
{
public function log($message)
{
...
… write $message to database using $this->query() …
...
}
}
class Something
{
public function __construct(Logger $logger)
{
$this->logger = $logger;
}

public function doWork()


{
...
$this->logger->log(...);
...
}
}
How do we make
the type hint work?
Interfaces
interface Loggable
{
public function log($message);
}
class FileLogger implements Loggable
{
protected $file;

public function __construct($file)


{
$this->file = $file;
}

public function log($message)


{
...
file_put_contents($this->file, $message, FILE_APPEND);
...
}
}
class DatabaseLogger extends DbGateway implements Loggable
{
public function log($message)
{
...
… write $message to database using $this->query() …
...
}
}
class Something
{
public function __construct(Loggable $logger)
{
$this->logger = $logger;
}

protected function doWork()


{
...
$this->logger->log(...);
...
}
}
$logger = new FileLogger('/path/to/logfile');

$something = new Something($logger);


$something->doWork();
$logger = new DatabaseLogger($dsn);

$something = new Something($logger);


$something->doWork();
$logger = new DummyLogger();

$something = new Something($logger);


$something->doWork();
class DummyLogger implements Loggable
{
public function log($message)
{
}
}
Interfaces make
good type hints.
Abstract Classes
and Methods
class Something
{
public function run()
{
// initialize

// perform calculations

// write log entry


// 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();

public function run()


{
$this->initialize();
$this->calculateStuff();
$this->doLogging();
$this->sortOutput();
}
}
abstract class Something
{
abstract protected function initialize();
abstract protected function calculateStuff();
abstract protected function doLogging();
abstract protected function sortOutput();

public function run()


{
$this->initialize();
$this->calculateStuff();
$this->doLogging();
$this->sortOutput();
}
}
abstract class Something
{
abstract protected function initialize();
abstract protected function calculateStuff();
abstract protected function doLogging();
abstract protected function sortOutput();

final public function run()


{
$this->initialize();
$this->calculateStuff();
$this->doLogging();
$this->sortOutput();
}
}
class ConcreteSomething extends Something
{
protected function initialize()
{
}

protected function calculateStuff()


{
}

protected function doLogging()


{
}

protected function sortOutput()


{
}
}
Abstract classes
cannot be instantiated.
„Every pattern describes a problem
which occurs over and over again in
our environment, and then describes
the core of the solution to that problem,
in such a way that you can use this
solution a million times over, without
ever doing it the same way twice.“

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

public function notify();


}
interface SplObserver
{
public function update(SplSubject $subject);
}
class Subject implements SplSubject
{
protected $observers;

public function __construct()


{
$this->observers = new SplObjectStorage();
}

...
}
class Subject implements SplSubject
{

public function attach(SplObserver $observer)


{
$observers->attach($observer);
}

public function detach(SplObserver $observer)


{
$observers->detach($observer);
}

...
}
class Subject implements SplSubject
{
...

public function notify()


{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
class Something extends Subject implements SplSubject
{
public function doWork()
{

foreach ($items as $item) {

$this->notify();
}
...
}
}
class ProgressBar implements SplObserver
{
public function update(SplSubject $subject)
{
print '. ';
}
}
class Something extends Subject implements SplSubject
{
public function doWork()
{

foreach ($items as $item) {
$this->currentItem = $item;

$this->notify();
}
...
}

public function getCurrentItem()


{
return $this->currentItem()
}
}
class ProgressBar implements SplObserver
{
public function update(SplSubject $subject)
{
$item = $subject->getCurrentItem();

}
}
class ProgressBar implements SplObserver
{
public function update(SplSubject $subject)
{
$item = $subject->getCurrentItem();

if ($item->isDir()) {
print '[' . $item->getPathname() . '] ';
}

if ($item->isFile()) {
print '.';
}
}
}
$progressBar = new ProgressBar();

$something = new Something();


$something->attach($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
{
}

class Airbus extends Plane


{
}

class Boeing777 extends Boeing


{
}

class AirbusA340 extends Airbus


{
}
$a = Plane::getInstance('Boeing777');

$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('...');
}

return new $type;


}
}
abstract class Plane
{
static public function getInstance($type)
{
if (!class_exists($type)) {
throw new RuntimeException('...');
}

return new $type;


}
}
abstract class Plane
{
protected $classMap = array(
'777' => 'Boeing777',
...
);

static public function getInstance($type)


{
if (!isset($this->classMap[$type])) {
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;

static public function getInstance()


{
if (is_null(self::$instance))
{
self::$instance = new Singleton();
}

return self::$instance;
}
}
class Singleton
{
static protected $instance;

private function __construct() {}


private function __clone() {}

static public function getInstance()


{
if (is_null(self::$instance))
{
self::$instance = new Singleton();
}

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;

static public function getDbAdapter()


{
if (is_null(self::$dbAdapter)) {
self::$dbAdapter = new DbAdapter();
}

return self::$dbAdapter;
}
}

$db = Registry::getInstance()->getDbAdapter();
...
class SingletonRegistry
{
static protected $instance;

protected $dbAdapter;

static public function getInstance()


{

}

public function getDbAdapter()


{
if (is_null($this->dbAdapter)) {
$this->dbAdapter = new DbAdapter();
}

return $this->dbAdapter;
}
}
class Registry
{

protected $dbAdapterClass = 'DbAdapter';


protected $dbAdapter;

public function setDbAdapterClass($class)


{
$this->dbAdapterClass = $class;
}

public function getDbAdapter()


{
if (is_null($this->dbAdapter)) {
$classname = $this->dbAdapterClass;
$this->dbAdapter = new $classname;
}

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

HTTP Request HTTP Response

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.

Please rate me:


http://joind.in
Contact
■ http://thePHP.cc
■ http://www.priebsch.de
■ http://www.slideshare.net/spriebsch
■ http://twitter.com/spriebsch
■ stefan@thePHP.cc, IRC: spriebsch

Copyright © 2009 thePHP.cc, Germany

You might also like