IntroductionWelcome| 00:04 | (music playing)
| | 00:04 | Hi! I'm Jon Peck, and welcome to
Object-Oriented Programming with PHP.
| | 00:09 | In this course, we'll look at the
fundamentals of object-oriented programming
| | 00:12 | with practical PHP examples.
| | 00:15 | I'll start by showing you how PHP
implements classes and properties by
| | 00:19 | creating an object.
| | 00:20 | Then, show you how PHP's magic
methods and class relationships work.
| | 00:24 | We'll build a system for storing
street addresses that uses design patterns.
| | 00:27 | We'll be covering all these topics,
plus plenty of other tools and techniques
| | 00:31 | used in PHP applications all around the web.
| | 00:35 | Let's get started with Object-
Oriented Programming with PHP.
| | Collapse this transcript |
| Exercise files| 00:00 | In this course, we'll be using PHP
on a web server that uses a database.
| | 00:04 | I recommend using Apache 2
or higher as the web server.
| | 00:08 | The code should run on other web
servers like NGINX or IIS, but I won't be
| | 00:12 | demoing with that configuration.
| | 00:13 | For the database, use MySQL 5 or above.
| | 00:17 | Finally, you'll need PHP 5.3 with the
MySQLi extension installed, which should
| | 00:21 | be there by default.
| | 00:23 | Setting up a development server
is out of the scope of this course.
| | 00:26 | If you need one, I prefer a virtual dev
server running on my workstation, like
| | 00:30 | the one shown in Up and Running with
Linux for PHP Developers here in the
| | 00:34 | Lynda.com Online Training Library.
| | 00:36 | I'll be demoing using this configuration.
| | 00:39 | If you'd like, a local web
server stack package will also work.
| | 00:42 | XAMPP from apachefriends.org has
distros for Mac, Windows, and Linux.
| | 00:48 | There's also WampServer from wampserver.
com, which is only for Windows and MAMP
| | 00:52 | from mamp.info for Macs only.
| | 00:55 | All three of these stacks
will work for this course.
| | 00:57 | If you'd like to learn more about local
web stacks, check out Installing Apache,
| | 01:01 | MySQL, and PHP with David Gassner here
in the Lynda.com Online Training Library.
| | 01:07 | If you'd prefer not to set up a local
dev environment, third-party hosted
| | 01:11 | servers will work as long as they have the
appropriate versions of Apache, MySQL, and PHP.
| | 01:17 | This is a common configuration, so
finding a host shouldn't be a problem.
| | 01:21 | The exercise files for this course are
arranged in folders by chapter and movie.
| | 01:25 | On my workstation, I've put them in a
folder on the desktop named 'sandbox' that
| | 01:29 | my virtualized Linux server can access.
| | 01:32 | Depending on your config,
your location may be different.
| | 01:36 | Regardless of your setup, you'll need
to import the contents of the free sample
| | 01:39 | data in demo.sql into a
database that you have access to.
| | 01:43 | This file contains the
schema and sample addresses.
| | 01:47 | To follow along with the demos,
you'll need a way to edit your PHP code.
| | 01:51 | I'll be using the free IDE
NetBeans 7.1 for PHP from netbeans.org.
| | 01:57 | NetBeans is not required for this course, but
it may be easy to follow along if you have it.
| | 02:02 | Finally, as different web hosts and
configurations serve content from different
| | 02:06 | URLs, the address you'll be seeing in
my browser may not be an exact match from
| | 02:10 | what you see on your workstation.
| | 02:12 | With that said, the end
result should look about the same.
| | Collapse this transcript |
| What you should know| 00:00 | This course was written with the
assumption that you have some basic knowledge
| | 00:03 | with PHP, and have written a few scripts.
| | 00:05 | Without this knowledge, you are probably
going to have a hard time following along.
| | 00:09 | If you need a refresher, I recommend
PHP with MySQL Essential Training with
| | 00:14 | Kevin Skoglund here in the
Lynda.com Online Training Library.
| | 00:18 | While you should have some PHP
knowledge, you're not going to need
| | 00:21 | object-oriented experience.
| | 00:22 | If you'd like to explore object-oriented
programming at a higher level, including
| | 00:26 | some of the underlying theories, I
recommend Foundations of Programming:
| | 00:30 | Object-Oriented Design with
Simon Allardice here in the Lynda.com
| | 00:34 | Online Training Library.
| | 00:36 | In this course, we'll be building
a simple application that stores
| | 00:39 | physical addresses.
| | 00:41 | It will be incremental development,
starting with just a simple address, then
| | 00:44 | building out to the point where the
address can display itself, load from the
| | 00:48 | database, and much more.
| | 00:49 | There will be three types of addresses:
| | 00:52 | residences, businesses, and parks. And,
each is going to have unique behaviors.
| | 00:57 | I'll also demo several design patterns
that solve common programming problems.
| | 01:01 | At the end, you'll have a stand-alone
component that could be integrated into a
| | 01:05 | larger application, along with new
strategies and tools at your disposal.
| | 01:09 | But let's not get ahead of ourselves.
| | 01:11 | We'll start with an introduction
to object-oriented programming.
| | Collapse this transcript |
|
|
1. Introduction to Object-Oriented ProgrammingWhat is an object?| 00:00 | In this chapter, I'm going to
introduce some key concepts about
| | 00:03 | object-oriented programming.
| | 00:05 | Starting with what objects
are, I'll then define classes.
| | 00:09 | Like any technique, it's good to
know why you should use object-oriented
| | 00:12 | programming. And, there are a number of reasons.
| | 00:14 | Finally, I will give a little history
of object-oriented PHP, as it's evolved
| | 00:18 | quite a bit over the years.
| | 00:20 | If I were to define object-oriented
programming as programming with objects,
| | 00:23 | that wouldn't be very helpful at all.
| | 00:25 | Instead, I'll start small, and build up.
| | 00:28 | In computer science, a primitive
data type is a basic, simple type of data
| | 00:32 | provided by a programming language.
| | 00:35 | Think of it as a building block, as
larger, more complex structures can be
| | 00:39 | built using primitives.
| | 00:41 | Some examples of primitives in PHP
include Booleans, which are a logical data
| | 00:45 | type containing either True or False;
integers, which are a numeric data type
| | 00:50 | that holds a whole number without any fractions.
| | 00:53 | Examples include -6 and 42.
| | 00:56 | Getting slightly more
complex are floating-point numbers.
| | 01:00 | Floats are a numeric data type as well,
but they can have fractional values.
| | 01:04 | Examples include 98.6 and -25, as floats
don't have to have a fractional value.
| | 01:11 | Finally, strings, which
contain a sequence of characters.
| | 01:14 | An example of a string would
be the phrase "hello, world."
| | 01:18 | Using the building blocks of primitives,
more complex data structures can be
| | 01:22 | built, which are known as objects.
| | 01:24 | An object can contain multiple
data types, each with their own values.
| | 01:28 | There is no restriction on the
number or the combination of data types.
| | 01:32 | You can have two strings, or a float
and a Boolean, or no data types at all.
| | 01:36 | To help illustrate my point,
I'll compare primitives to objects.
| | 01:40 | For example, consider a
string containing the word "Toronto."
| | 01:44 | It's a simple data type with a single value.
| | 01:47 | In comparison, an object representing
a physical address may have multiple
| | 01:51 | data types, each with their own values, such
as the street number, city, and subdivision.
| | 01:56 | The value stored for the city could be
a string containing the word "Toronto."
| | 02:01 | Each value in an object is stored as a
property, which I'll explore in a moment.
| | Collapse this transcript |
| What is a class?| 00:00 | While primitives have fixed data
structures, objects in comparison can seem
| | 00:04 | loose, in that they can
have any number of properties.
| | 00:07 | To give structure to an
object, I can use a class.
| | 00:10 | A class is a blueprint that
defines the structure of an object.
| | 00:14 | Objects are created in the exact
same way using these class blueprints.
| | 00:18 | This way, I know that when a class is
used as a blueprint for an object, the
| | 00:22 | structure of each object won't be different.
| | 00:24 | Each class modularizes program
functionality by separating features with as
| | 00:29 | little overlap as possible.
| | 00:30 | Classes have attributes, which are
the data structure for properties.
| | 00:34 | There is a tiny technical difference
between attributes and properties, but it's
| | 00:38 | so minor that even the official PHP
documentation uses the terms kind of
| | 00:42 | interchangeably, and prefers properties.
| | 00:45 | So, we'll also use properties.
| | 00:46 | Classes also define behaviors,
which are implemented as methods.
| | 00:50 | A method is a subroutine
that works on an object.
| | 00:54 | I like to think of methods like a
function that's contained within a class.
| | 00:58 | Objects are instances of a class,
meaning each occurrence of an object of a
| | 01:02 | particular class has all the
properties and behaviors of that class.
| | 01:06 | The individual properties will be
the same, but the value stored in the
| | 01:10 | properties may differ.
| | 01:11 | As an example, I'm going to
define a class for an address.
| | 01:15 | The class address has several
properties like the city, and subdivision, and
| | 01:19 | has the behavior of being able to look up a
postal code given the values of those properties.
| | 01:24 | Therefore, every instance of class
address will have those properties and behavior.
| | 01:30 | I'm going to apply this address class
to the real world using two instances.
| | 01:34 | The first instance can represent
Phoenix, Arizona, and the second instance can
| | 01:38 | represent Columbus, Ohio.
| | 01:41 | As each object is an instance of class
address, I know that they should have at
| | 01:45 | least a city and subdivision. And, I know
that it has the behavior of postal code lookup.
| | 01:50 | I can't anticipate the contents of the
object properties, but I can anticipate
| | 01:54 | their format, and how to access them.
| | 01:57 | This seems like a lot of work.
| | 01:58 | I know that I can write code that works
perfectly fine without defining classes
| | 02:02 | with properties and behaviors.
| | 02:04 | So, why bother using
object-oriented programming?
| | Collapse this transcript |
| Why should you use object-oriented programming?| 00:00 | There are a number of very
practical reasons for using object-oriented
| | 00:03 | programming, and not just
because it looks good on paper.
| | 00:06 | The short reason? Object-oriented
programming organizes projects into
| | 00:10 | consistent, manageable pieces.
| | 00:12 | As a developer, I've come to really
appreciate well-organized code, as it
| | 00:16 | saves time and money.
| | 00:18 | In comparison, procedural programming is
a set of step-by-step instructions that
| | 00:22 | the computer must follow.
| | 00:24 | A procedural program can consist of a
series of conditions, and function calls
| | 00:27 | for logic, but the end result is very linear.
| | 00:30 | Meaning, program
execution is like a straight line,
| | 00:33 | rigid and inflexible.
| | 00:34 | There's nothing wrong with procedural
programming, and for small projects, it
| | 00:38 | can be a good solution.
| | 00:40 | The problem comes when you scale up.
| | 00:42 | You may find yourself defining arrays
with long descriptive keys, or passing
| | 00:46 | large numbers of global variables
between scripts, or even searching for a
| | 00:50 | non-fatal bug across a dozen squares
with thousands of lines of code with little
| | 00:54 | indication of which component is at fault.
| | 00:56 | Object-oriented programming introduces
structure intended to avoid the scaling
| | 01:00 | and maintenance issues.
| | 01:02 | Throughout this course, I am going
to explore a number of features of
| | 01:05 | object-oriented programming,
including abstraction, which defines data and
| | 01:09 | program structures using a
representation of meaning, while hiding the
| | 01:13 | implementation itself.
| | 01:14 | This allows for the use of human readable
terminology to be used as part of the software.
| | 01:19 | Next is encapsulation, which exposes
functionality while restricting access to
| | 01:24 | low-level components and data.
| | 01:26 | You can also introduce a hierarchy
where properties and behavior from
| | 01:29 | pre-existing classes are inherited,
which allows for incremental development.
| | 01:33 | Another feature is modularity, where
functionality is broken into modules that
| | 01:37 | accomplish one task, and contain
everything necessary to complete said task.
| | 01:41 | Instead of trying to deal with one
large problem, a number of smaller
| | 01:45 | sub-problems work together
to solve the bigger problem.
| | 01:48 | And finally, polymorphism, which is the
ability to interact with classes in the
| | 01:52 | same way without having to
know exactly which class they are.
| | 01:55 | By using object-oriented programming,
you can build small components that can be
| | 01:59 | easily maintained and expanded upon
without messing up the entire program.
| | 02:03 | That way, you can create and test the
program in small pieces, rather than trying
| | 02:07 | to deal with huge, messy code.
| | 02:09 | But has PHP always supported this
kind of object-oriented programming?
| | Collapse this transcript |
| The history of object-oriented PHP| 00:00 | It turns out that object-oriented
programming is not a relatively modern concept,
| | 00:04 | with historical references
going back as far as the 1960s.
| | 00:08 | PHP didn't have object-oriented
features until version 3 in 1998, which included
| | 00:13 | basic class and object support.
| | 00:14 | It wasn't complete, but it was a start.
| | 00:17 | Two years later, in 2000, PHP 4 added
more support, but suffered from some
| | 00:21 | weirdness coming from variable
assignments and references, leading to confusing
| | 00:24 | code and high memory usage.
| | 00:26 | Finally, PHP 5 came out in 2004,
including an extensive rewrite of object
| | 00:32 | handling with the introduction of Zend
Engine 2, which featured a full feature
| | 00:35 | set and greatly increased performance.
| | 00:38 | At that point, PHP had a complete object
model, which had been missing from prior versions.
| | 00:43 | Since then, most major modern PHP
frameworks utilize or are transitioning to an
| | 00:48 | implementation that
leverages PHP 5's object support.
| | 00:51 | Throughout this chapter, I've
explored some of the fundamentals of
| | 00:54 | object-oriented programming.
| | 00:56 | Starting with the definition of an
object, I expanded to describe what classes
| | 01:00 | are, then gave a number of reasons why
object-oriented programming was good.
| | 01:04 | I closed with a brief history
of PHP's support of objects.
| | 01:08 | This all looks good on paper, and if
you're anything like me, you've probably
| | 01:12 | had enough theory and are
ready to start writing code.
| | 01:15 | In the next chapter, I'm going to
do just that, starting with creating
| | 01:18 | an object.
| | Collapse this transcript |
|
|
2. Creating Your First ObjectDefining a class| 00:00 | In this chapter, we're going to create an
object, which will be an instance of an address class.
| | 00:05 | I'll start by describing how to
define a class and its properties.
| | 00:08 | Then, we'll add a behavior
to the class with a method.
| | 00:12 | I'll show you how to create an object,
and access its contents, then finally, how
| | 00:15 | to protect those contents
from the rest of the program.
| | 00:18 | Throughout this course, we'll be
building upon this address class.
| | 00:21 | So, remember to save often as you progress.
| | 00:24 | Ready to start coding?
| | 00:25 | Switch to your editor, and create a new file.
| | 00:30 | The same PHP file-naming conventions
apply to files that contain classes.
| | 00:35 | Many coding standards have file
naming and content conventions as well.
| | 00:39 | For readability, let's name the file
containing the example class something logical.
| | 00:44 | class.Address.inc.
| | 00:47 | I'm using the extension INC, short for
include, to indicate that this file is
| | 00:52 | intended to be included,
and not executed on its own.
| | 00:57 | Class definitions always start with the
keyword "class" followed by the name of the class.
| | 01:01 | There are three PHP rules regarding
the naming convention used for classes.
| | 01:05 | First, the class name must
start with a letter or underscore.
| | 01:09 | Then, any remaining characters must
only be letters, numbers, or underscores.
| | 01:13 | Finally, there's no limit on
the length of the class name.
| | 01:17 | There are a number of best practices
for naming a class to make reading and
| | 01:20 | sharing code easier.
| | 01:22 | Conventions differ between coding
standards, but a common theme tends to be the
| | 01:25 | use of uppercamel naming, meaning the
first letter of each word is capitalized.
| | 01:30 | In contrast, it's best to name variables in
lowercase, which makes them easy to tell apart.
| | 01:35 | Finally, it's best practice to avoid
the name "class" when naming a class, because
| | 01:39 | it's frankly confusing.
| | 01:41 | Following the class name is a pair of
curly braces that enclose any properties
| | 01:45 | and methods that belong to the class.
| | 01:48 | PHP allows the contents of the class
to be empty, so I'll get into greater
| | 01:51 | detail about both
properties and methods in a moment.
| | 01:55 | First, I want to demonstrate
some good and bad class names.
| | 01:58 | Here are some practical examples of
class creation in PHP. class Address.
| | 02:05 | This is valid, as it starts with a letter,
and the remaining characters are also letters.
| | 02:10 | class PhysicalAddress.
And, class Physical_Address.
| | 02:21 | Each of these is valid, and follows
common best practices for capitalization.
| | 02:26 | The use of underscores for word
separation differs between coding standards.
| | 02:31 | class physical_address,
but this time in lowercase.
| | 02:36 | This is valid, but not a best practice as
each word does not start with a capital letter.
| | 02:41 | class 21_jump_street.
| | 02:46 | This class name is invalid.
| | 02:48 | It will trigger a parse error, expecting
t-string, because it starts with a number.
| | 02:52 | Now that we've got a way of
defining a class, let's start populating it
| | 02:56 | with properties.
| | Collapse this transcript |
| Defining class properties| 00:00 | As you may recall, a class property
is a structure for storing values.
| | 00:04 | A class can have any number of
properties associated with it.
| | 00:07 | Each property is defined
with a visibility keyword:
| | 00:10 | public, protected, or private.
| | 00:12 | If you leave out the keyword,
you're going to get a parse error.
| | 00:15 | I'll explore visibility scope in
greater detail in a later video.
| | 00:19 | For the time being, let's just stick
with public properties that have no
| | 00:22 | access restrictions.
| | 00:24 | Properties are declared kind of like
regular variables, including the naming
| | 00:28 | conventions for PHP labels.
| | 00:30 | Same as class naming, property
names must either start with a letter or
| | 00:33 | underscore, then be followed by any
number of letters, numbers, and underscores.
| | 00:38 | When naming a property, a best
practice is to use lowerCamel naming, meaning
| | 00:42 | the first letter of the name needs to be
lowercase, and then the first letter of
| | 00:46 | any remaining words should be capitalized.
| | 00:49 | Avoid naming a public property
with an underscore at the beginning.
| | 00:52 | Depending on the coding standard, this
may visually indicate that it's actually
| | 00:55 | private access only.
| | 00:57 | When you're declaring a property, you can
optionally initialize it with the default value.
| | 01:01 | If you do, it must be an unchanging value.
| | 01:05 | This means that it must be able
to be evaluated upon compilation.
| | 01:08 | So, things that change, like the
current time, are not allowed.
| | 01:12 | Let's clean up all the test code,
then build upon the first address class.
| | 01:16 | public $streetName.
| | 01:20 | This is a valid property name
that follows best practices.
| | 01:23 | public $subdivision_name = California.
| | 01:28 | This is also a valid property name that
includes an initialization. public $_city.
| | 01:35 | This is a valid property name, but as
described before, does not follow best
| | 01:39 | practices by implying that it
has a different variable scope.
| | 01:43 | public $time_updated = time.
| | 01:47 | This is a valid property name, but as
the value is determined at runtime, this
| | 01:51 | is an illegal initialization,
and will generate a parse error.
| | 01:55 | public $-addressId.
| | 01:58 | This is an invalid property name, as it
starts with a dash, not an underscore.
| | 02:03 | This will generate a parse
error, expecting a T variable.
| | 02:07 | public $city_copy = $_city.
| | 02:12 | This is an invalid initialization, as
it depends on a runtime evaluation.
| | 02:16 | So, it will also trigger a parse error.
| | 02:19 | Let's clean up this example, and make it
useful in a real world application, and
| | 02:23 | add some documentation.
| | 02:25 | For the time being, I'll use human
readable data for properties with known
| | 02:29 | domains, such as the city,
subdivision, and country name.
| | 02:37 | We'll start with basic class documentation.
| | 02:40 | I will add the street address properties.
| | 02:42 | public $street_address_1,
public $street_address_2.
| | 02:50 | Following the address, let's add the structure
for the name of the city. public $city_name.
| | 02:57 | After the city, I'll add
the name of the subdivision.
| | 03:00 | This can be a state,
territory, region, and so forth.
| | 03:03 | public $subdivision_name.
| | 03:08 | Most addresses have a postal code of some sort.
| | 03:10 | public $postal_code. And
finally, the name of the country.
| | 03:18 | public $country_name.
| | 03:21 | Now that we have a class definition,
let's save it before we move on to creating
| | 03:25 | a method in the next video.
| | Collapse this transcript |
| Creating a method and exploring object context with $this| 00:00 | Another structural
feature of classes are methods.
| | 00:03 | A method is pretty much a
function within a class.
| | 00:06 | Methods follow the same naming
conventions as regular functions, which are the
| | 00:10 | same as the rest of the PHP labels.
| | 00:12 | Best practice dictates a similar
naming convention to properties with
| | 00:15 | lowerCamel case naming.
| | 00:18 | The first method we're going to build
meets a common need, displaying an address
| | 00:21 | with HTML formatting.
| | 00:24 | The end result will look something
like 555 Fake Street, Townsville, State
| | 00:28 | 12345, United States of America.
| | 00:32 | To keep us focused, I'm not going to
include any type of data sanitizing
| | 00:35 | when rendering the data.
| | 00:37 | To make this production-ready, you
should use something like htmlspecialchars, as
| | 00:41 | users should never be trusted.
| | 00:44 | In the ID, let's start with a sub
declaration for the display method.
| | 00:48 | function display. output
is empty. return output.
| | 00:57 | Let's add proper documentation.
Display an address in HTML.
| | 01:03 | In order to display the contents of an
address, I need to be able to access the
| | 01:07 | properties of the object.
| | 01:09 | If I'm using a method within the object,
I can use the pseudo variable "$this."
| | 01:14 | $this is a reference to the calling
object, which is almost always the object
| | 01:18 | that the method belongs to.
| | 01:20 | To access properties of an object using
$this, append "->" to $this, followed by
| | 01:25 | the name of the property without a dollar sign.
| | 01:28 | For example, if I have an address
instance with a property named "city" and a
| | 01:32 | value of "San Diego," a method that
accesses this city will be able to get the
| | 01:37 | contents of the city
property, which is San Diego.
| | 01:41 | Back to the display function.
We'll start with a street address.
| | 01:44 | $output = $this->street_
address_1. And, then some logic.
| | 01:50 | If there is a street_address_
2, display it on a new line.
| | 02:02 | Next, we'll have the City,
Subdivision, and the Postal Code.
| | 02:08 | Output, new line, output the city name
followed by a comma, then subdivision
| | 02:21 | name, space, and the postal code. Finally, the
country, new line, and then the country name.
| | 02:40 | Now that the method definition
is complete, I'll save the file.
| | 02:45 | In the next movie, we'll take a
look at instantiating an object, and
| | 02:48 | accessing its contents.
| | Collapse this transcript |
| Instantiating an object and accessing its contents| 00:00 | So far, I've created an address class,
given it a number of logical properties
| | 00:04 | for storing data, and declared a display method.
| | 00:08 | It's time to put it to good use by
creating an instance of the address class.
| | 00:12 | This process is referred to as
instantiation, and the result is an object of
| | 00:16 | the instantiated class.
| | 00:18 | To create an instance of a class,
start with a variable declaration.
| | 00:21 | Then use the new keyword followed by the
name of the class that you wish to instantiate.
| | 00:27 | Let's create a new file named demo.php,
and place it in the same folder as
| | 00:33 | your address class.
| | 00:35 | At the top of the file,
require the address class.
| | 00:39 | Next, create a new variable named
address assigned to the new address.
| | 00:44 | Add the following lines:
| | 00:46 | echo <h2>Instantiating
Address, $address = new Address.
| | 00:55 | For debugging purposes, you can inspect
the contents of the entire object using
| | 00:59 | var dump and var export.
| | 01:02 | Add the following lines:
| | 01:04 | echo <h2>Empty Address, echo <tt><pre>
var_export $address, followed by TRUE,
| | 01:19 | and close </pre></tt>, save, then open
your web browser, and navigate to the
| | 01:26 | location of your exercise files.
| | 01:31 | You should see the object of class address
displayed with all properties set to null.
| | 01:36 | As you may recall, you can access the
properties of an object using the object
| | 01:40 | property access syntax, '->'.
| | 01:43 | You can both get and set these properties.
| | 01:46 | Set each of the properties of
the address, then debug the result.
| | 01:50 | Go back to the demo source:
| | 01:55 | echo, setting properties, $address->
street_address_1 = '555 Fake Street',
| | 02:07 | $address->city_name = 'Townsville',
$address->subdivision_name is State,
| | 02:18 | $address->postal_code = '12345', $address->
country_name is the United States of America.
| | 02:33 | We'll debug the object at
the end using var export. Save.
| | 02:37 | Now, let's switch back to the code, and
refresh your browser to see the populated address.
| | 02:42 | In addition to properties, you can
also access an object's class method
| | 02:46 | using the same syntax.
| | 02:48 | Display the address in the demo file.
| | 02:51 | Now, let's switch back to the code:
| | 02:54 | echo displaying address, and echo address
and the display method, save, and refresh.
| | 03:05 | You've now instantiated your first
object, manipulated its properties, debugged
| | 03:10 | its contents, and executed a method.
| | 03:13 | In the next segment, I'm going to
explore how access can be controlled to
| | 03:16 | properties and methods using visibility.
| | Collapse this transcript |
| Specifying the visibility scope| 00:00 | As previously mentioned, visibility of a
property or a method is defined using a
| | 00:05 | scope keyword: public, protected, or private.
| | 00:09 | If a method or property is defined as
public, it means that it can be both
| | 00:13 | accessed, and properties can be changed
by anything that can refer to the object.
| | 00:18 | Sometimes that's a good thing.
| | 00:19 | You may have no need to restrict
access to a property or method.
| | 00:23 | For example, public methods can be
exposed as part of an application
| | 00:27 | programming interface or API.
| | 00:29 | As an abstract example, think of public like
a picnic that everybody is welcome to join.
| | 00:35 | If defined as protected, members can
only be accessed within the class itself,
| | 00:39 | and by inherited and inheriting classes.
| | 00:42 | Inheritance will be covered in a
later video, but in short, a class can have
| | 00:46 | all the properties and methods of another class.
| | 00:49 | The end result is a superset of all the
methods and properties of both classes.
| | 00:54 | The class that is inheriting the
methods and properties is referred to as the
| | 00:58 | child, and the class from which the
methods and properties are coming from is
| | 01:02 | known as the parent.
| | 01:03 | Therefore, a protected member from the
parent would be accessible by the child.
| | 01:08 | However, regular code or a different
class that was unrelated to the parent
| | 01:12 | class would not be able to access the
protected property or method. To continue
| | 01:16 | with the picnic example, think it of as a
company picnic where family members of
| | 01:20 | the employees are allowed,
but not the general public.
| | 01:24 | When restricting visibility,
| | 01:25 | protected is the most common scope restriction.
| | 01:28 | Finally, if a method or property is
defined as private, only the class that has
| | 01:33 | the private members can access those
methods or properties, despite whatever
| | 01:37 | relationships between classes there may be.
| | 01:40 | With the picnic example, only company
employees will be allowed; family members
| | 01:44 | and the public are excluded.
| | 01:46 | In regular practice, private
visibility is used less often, as it can cause
| | 01:50 | headaches and bugs that are created
by humans writing code when dealing
| | 01:53 | with class hierarchy.
| | 01:54 | So, use it sparingly.
| | 01:57 | Let's extend the address class by
adding some protected properties.
| | 02:00 | We will add three protected properties:
| | 02:02 | a primary identifier for the table
that will be accessed later, a time
| | 02:06 | created, and a time updated.
| | 02:09 | We are protecting them, as we do not
want them to be accessed directly.
| | 02:12 | This is internal information that
should not be manipulated by anything other
| | 02:16 | than the address class and
anything that's associated with it.
| | 02:19 | A best practice to visually
indicate that a method or property has been
| | 02:22 | protected is to prepend the name
with a single underscore (_) character.
| | 02:27 | Open the Address class, then
navigate to after the property declarations.
| | 02:33 | We'll start with the primary key of an
address. protected $_address_id. Next,
| | 02:47 | when the record was created and
last updated. protected $_time_created.
| | 02:55 | protected $_time_updated.
| | 02:59 | Save the address class. Test out these
new protected properties by adding the
| | 03:03 | following line to the end of the demo:
echo h2 Testing protected access.
| | 03:16 | Echo. Double quotes this time.
| | 03:18 | Address_ID ($address->_address_ID].
This will intentionally fail. Save, then
| | 03:29 | refresh your browser. We'll get a
fatal error about accessing the protected
| | 03:35 | properties, which is just what we're expecting.
| | 03:38 | In this chapter, we've built upon
object-oriented theory with some
| | 03:41 | practical examples.
| | 03:43 | Starting with the class definition, we
added properties to store things like
| | 03:47 | the city and street.
| | 03:48 | We created a method to render the
address in HTML, then we instantiated an object
| | 03:53 | of class address, accessing
and manipulating the contents.
| | 03:57 | Finally, we restricted access by
specifying the visibility scope.
| | 04:01 | This resulted in a fatal error.
| | 04:02 | So, in the next chapter, I'll
demonstrate how to correctly access these
| | 04:06 | protected properties.
| | Collapse this transcript |
|
|
3. Overloading with Magic MethodsWhat is a magic method, and do I need one?| 00:00 | So, far we've barely scratched the
surface of PHP's object-oriented support.
| | 00:05 | In this chapter, I am going to show you
how to take advantage of some of PHP's
| | 00:08 | built-in methods that have a
unique name: magic methods.
| | 00:12 | I'll start by describing just what
magic methods are and then we'll see how to
| | 00:16 | write code that is able to make
logical guesses when something is missing.
| | 00:20 | We'll explore how to customize how
objects are created, and then finally, make
| | 00:24 | an object display itself.
| | 00:25 | So, what exactly is a magic method?
| | 00:28 | Magic Methods are a collection of
specialized methods that have been built into
| | 00:32 | PHP that execute in
response to a particular event.
| | 00:36 | There are about a dozen magic methods available.
| | 00:39 | The naming convention for
magic methods is consistent.
| | 00:42 | Each magic method name starts with two
underscores, such as _construct() and _toString().
| | 00:48 | I can't name a method with one of
these special names without triggering
| | 00:52 | the magical behavior.
| | 00:53 | With that said, due to the unique
naming convention, you probably won't ever
| | 00:57 | accidentally create a function
with the same name as a magic method.
| | 01:01 | Magic methods can be very useful. I
can trigger custom behavior upon specific
| | 01:05 | events, such as attempting to access a
non-available property, or calling a
| | 01:09 | method that doesn't exist.
| | 01:11 | I can also customize the creation of
an object, and set defaults that aren't
| | 01:15 | available at run time, such as the
logged in user, or the current time.
| | 01:19 | This all sounds good, but what's the cost?
| | 01:22 | Magic methods have an overhead, leading
to code execution that is anywhere from
| | 01:26 | 3 to 20 times slower for
that particular method call.
| | 01:29 | They also ignore scope, meaning that
you can accidentally expose a property or
| | 01:33 | method that is normally hidden
from the rest of the program.
| | 01:36 | Finally, magic methods can break code
completion in IDE's, meaning the IDE can
| | 01:41 | follow the logic, and may assume that
you're trying to access something that
| | 01:44 | doesn't exist, and that you're wrong.
| | 01:46 | With all that said, weigh the pros and
cons of any technique before implementing it.
| | 01:50 | It may be worth your IDE unnecessarily
warning you in exchange for a contextual
| | 01:55 | response to a request for
an inaccessible property.
| | 01:59 | The performance difference is able to
be detected in benchmarking with millions
| | 02:02 | of iterations, but in practical use,
the difference is pretty much nothing.
| | 02:06 | Sometimes, it can be useful to have
something that can logically decide whether
| | 02:10 | or not to expose something hidden by a scope.
| | 02:12 | My goal is to educate, and to allow you to
determine what approach is best for your needs.
| | 02:17 | There is no one right answer.
| | 02:19 | Well, that's enough time.
| | 02:20 | Let's start using magic methods.
| | Collapse this transcript |
| Overloading property access| 00:00 | Within PHP, overloading means to
dynamically create a property or method that has
| | 00:05 | not been declared, or is not
visible in the current scope.
| | 00:08 | When I say create, it's figurative.
PHP will act like they exist and can be
| | 00:12 | accessed, even though in reality they don't.
| | 00:15 | These dynamic entities are
processed using magic methods.
| | 00:19 | Object properties have two events that
can be invoked when accessing a missing
| | 00:23 | or out-of-scope property:
| | 00:25 | when a script _gets a property,
and when a script _sets a property.
| | 00:29 | They can be useful to do things like
use a method or function to determine the
| | 00:32 | value to be returned, or execute some
sort of failsafe behavior when trying to
| | 00:37 | set a property that doesn't exist.
| | 00:39 | Both the get and the set magic methods
have public visibility, so you don't have
| | 00:43 | to specify scope when declaring them.
| | 00:45 | In the Address class, a magic _get
method would be useful for calculating a
| | 00:49 | missing postal code.
| | 00:50 | For example, if the postal code was null,
but there is a city in subdivision, I
| | 00:55 | could attempt to look up the value in a table.
| | 00:58 | However, as the postal code is currently
public, the magic _get method won't be triggered.
| | 01:03 | Therefore, we'll change the scope of
the postal code to protected, in order to
| | 01:07 | be able to use the magic _get.
| | 01:09 | I'll demo the database lookup
later. For the time being, we'll put in a
| | 01:13 | placeholder and focus on magic methods.
| | 01:16 | Open the Address class, then change
the scope of postal code to protected.
| | 01:21 | Remember to prepend the property
name with an underscore (_) to visually
| | 01:24 | indicate the scope. Then start
editing the file after the last property
| | 01:28 | declaration. Add a placeholder function
for the database lookup for the postal code.
| | 01:34 | As there is no need to expose this
function outside of the address class,
| | 01:38 | protected as well. protected function _
postal_code_guess, return LOOKUP. Add
| | 01:50 | proper PHP documentation, guess the postal
code given the subdivision and city name, to do.
| | 02:00 | Replace with a database LOOKUP.
| | 02:04 | Now that you have a postal code
placeholder, you can now leverage the magic
| | 02:08 | _get method. They take only one argument,
the name of the property in the form
| | 02:12 | of a string. Place the Magic _get method
above the protected method, postal_code_guess.
| | 02:20 | function__get name. Then, documentation Magic _
get. Name as a string, and returns next.
| | 02:38 | Insert the logic for the special
behavior for the postal code property.
| | 02:43 | Postal code lookup if I set, if
no postal_code, and set postal code
| | 02:57 | to _postal_code_guess.
| | 03:02 | After the special condition for
postal code, you'll expose any protected
| | 03:06 | properties that start with an
underscore as read-only. Remember, this will get
| | 03:11 | around scope restrictions.
| | 03:12 | So, only do this if you are aware of
the potential consequences, such as
| | 03:15 | accidentally exposing internal data.
| | 03:18 | In this case, there is no harm in
exposing all protected properties as read-only.
| | 03:23 | Attempt to return a protected
property by name. You cannot call a property
| | 03:29 | using a concatenated string, so
create a variable that starts with the
| | 03:32 | underscore followed by the name.
| | 03:35 | $protected_property_name=_ followed by
$name. if property_exists in this with the
| | 03:46 | property name, return
this protected_property_name.
| | 03:54 | If the property does not exist,
trigger a PHP error and return null.
| | 04:03 | trigger_error Undefined property via _
get, followed by the name. return NULL.
| | 04:14 | If you were to test the script now, you
would get a failure when you attempted to
| | 04:17 | set the postal code, as
it is currently protected.
| | 04:20 | Therefore, you will also need to define
a magic _set to handle that circumstance.
| | 04:25 | Beneath the magic _get, define
a magic _set method.
| | 04:28 | The magic _set method has two arguments.
| | 04:31 | The first is the name of the property
as a string, and the second is a mixed
| | 04:35 | value to be set. function__set name, value.
Add the PHP documentation, string for
| | 04:46 | name, mixed for value.
| | 04:50 | Add the check for the postal code
property, and allow anything to manipulate it.
| | 04:54 | In this example, stick with a simple if
statement, as there is only one logical check.
| | 04:59 | If there were multiple property
names that you are checking for, a switch
| | 05:02 | statement may be more readable. Allow
anything to set the postal code. If postal
| | 05:11 | code is the name, this name = value. return.
| | 05:20 | If the property is not postal code,
trigger contextually appropriate error.
| | 05:25 | Unable to access property; trigger
error. trigger_error ('Undefined or
| | 05:37 | unallowed property via _
_set (); followed by the name);
| | 05:46 | Save the address class, then open
the demo file. At the end, remove the
| | 05:52 | unintentional failed display of address
ID. Then, let's test the new magic _get
| | 05:59 | method by unsetting the postal
code, and displaying the result.
| | 06:03 | echo <h2> Testing magic _get and _
set; unset ($address postal_code);
| | 06:08 |
| | 06:19 | echo $address_display();. Save the demo
file, then refresh your browser.
| | 06:25 | The first instance of the postal
code shows up as expected, and the second
| | 06:29 | instance with no postal
code now shows the word LOOKUP.
| | 06:32 | In the next video, you can set the
time created, leveraging a construction
| | 06:36 | magic method.
| | Collapse this transcript |
| Customizing object construction| 00:00 | Starting in PHP5, developers could
use a magic method for initializing new
| | 00:05 | objects. Before they were used. It's called _
construct (), and this magic method is Optional.
| | 00:10 | It's flexible enough that even can be
empty, which is the same as not having a
| | 00:14 | magic construct method at all.
| | 00:16 | If you don't need to initialize an
object, don't use it, as it's just wasted
| | 00:20 | code. Developers shouldn't be paid by the line.
| | 00:22 | In the Address class, I'm going to use the
magic construct method to set the creation time.
| | 00:27 | Let's open the Address class. Add the
following after the properties, before the
| | 00:32 | Magic _get and _set methods.
| | 00:33 | function __construct.
| | 00:37 | In its current form, this will have no
functional effect, neither positive nor negative.
| | 00:42 | If you are declaring a class, and have no
need to customize the constructor, leave it out.
| | 00:47 | In the case of your address, you
want to set the time created upon
| | 00:50 | initialization. In between the
brackets, add the following line: this
| | 00:57 | ->time_created = time(). Save the
address class, then rerun the demo.
| | 01:05 | In the debug, you'll see that time
created is now set. This technically works,
| | 01:10 | but it's impractical to specify each
property name when populating an object.
| | 01:14 | Fortunately, I can pass arguments to
the _construct() magic method, which I can
| | 01:18 | then use to optionally populate the object.
| | 01:21 | Let's go back to the Address class. data
= array. And some documentation. Optional
| | 01:37 | array of property names and values.
| | 01:42 | Next, add a sanity check by ensuring that
the argument is really an array. If not,
| | 01:47 | trigger an error and fail.
| | 01:50 | Ensure that the Address can be
populated. If not, array trigger_error. Unable to
| | 02:07 | construct address with a get_class$name.
| | 02:15 | If there is data in array, if there is
at least one value, populate the Address
| | 02:21 | with it. Iterate through the array.
| | 02:27 | Later, you will want to be able to set
the time created and time updated from
| | 02:31 | an existing record.
| | 02:32 | So, include logic for these protected
properties that will allow them to be
| | 02:36 | sent. Special case for protected
properties, if in_array name, array
| | 02:46 | time_created, and time_updated, $
name start with an underscore (_).
| | 02:57 | Finally, set the property. The existing
Magic _set() method will trigger an error
| | 03:02 | if you attempt to set an invalid
property. $this->name = $value.
| | 03:07 | You can now create a new address object
with an array of properties and values.
| | 03:11 | Save the Address class, then open the demo.
| | 03:14 | Start with a title. echo h2 Testing
Address __construct with an array.
| | 03:24 | Next, create a new address object, but
this time with an array as a property.
| | 03:29 | $address_2 is a new Address, which will
populate with an array. street_address_1
| | 03:39 | is 123 Phony Ave. The city_name is
Villageland, the subdivision_name is Region,
| | 03:55 | postal_code is 67890, and
the country_name is Canada.
| | 04:08 | Finally, display the result. echo $address_
2 display. Save and test in your browser.
| | 04:22 | You have laid the groundwork that will
allow for easy object population from a
| | 04:25 | database record that has
been returned as an array.
| | 04:28 | Next, you can simplify address
displaying by defining how the object is
| | 04:32 | rendered as a string.
| | Collapse this transcript |
| Standardizing object rendering as a string| 00:00 | Instead of just asking an object to
display itself, it's more convenient to assume
| | 00:05 | that when echoed, an object
knows to treat itself like a string.
| | 00:09 | At a high level, this concept is known
as polymorphism, where I can act on an
| | 00:13 | object without knowing exactly what
the class is. In practice, this means more
| | 00:18 | common function names between classes.
| | 00:20 | I am going to cover polymorphism
in greater depth in a later segment.
| | 00:25 | For now, let's focus on making an
address display as a string by echoing.
| | 00:30 | To do this, I'm going to use the magic
method _toString(), which allows an object
| | 00:35 | to specify how to return a string.
| | 00:37 | I am going to switch back to the demo
script. Then, at the end, add the following
| | 00:42 | lines: echo <h2>Address _toString. Then
echo $address_2. Refresh your browser.
| | 00:55 | You will see a catchable fatal error.
| | 00:57 | This is because the object does not have a
method defined to convert itself to a string.
| | 01:02 | Open the Address class. Under the
Magic _set() method, declare a new method
| | 01:10 | called _toString. Add the PHP
documentation. Magic _toString returns a string
| | 01:24 | As you already defined the method
to display the address, call it from
| | 01:28 | _toString, and return its value.
return this->display. Save, then return to
| | 01:35 | your browser, and refresh.
| | 01:38 | Instead of an error, you will see the
address rendered as if you called the display
| | 01:42 | method directly. This is just one
example of polymorphism, and I'll get into
| | 01:46 | sharing interfaces a bit later.
| | 01:49 | In this chapter, I've been focusing
on overloading with magic methods.
| | 01:53 | I started by defining just what magic
methods are, then demonstrated them by
| | 01:57 | overloading property access and by
restricting visibility. I customized object
| | 02:02 | construction by setting the time
that the object was created automatically,
| | 02:05 | then made an address treat itself
like a string, using polymorphism.
| | 02:09 | So far, we've worked with classes and
instances, but did you know that you can
| | 02:13 | access methods and properties
without instantiating an object?
| | Collapse this transcript |
|
|
4. Accessing Classes without InstantiationUsing the static keyword| 00:00 | Up to this point, the only way we've
used classes is by instantiating, which
| | 00:04 | can get a bit unwieldy.
| | 00:06 | In this chapter, I'm going to introduce
the concept of the static keyword, which
| | 00:10 | gets around this limitation.
| | 00:12 | I'll then demo how to access class
contents without instantiation, set
| | 00:16 | values that never change, and even
how to create a method that doesn't
| | 00:20 | require instantiation.
| | 00:21 | Finally, we'll put it all together,
and create a custom database class.
| | 00:25 | But before we do that,
let's start with the basics,
| | 00:28 | avoiding instantiating.
| | 00:30 | Sometimes, it's useful to access a
property or method of a class without the
| | 00:34 | overhead of actually instantiating an object.
| | 00:37 | Depending on the class, that
instantiation might include connections to a
| | 00:40 | database or third-party service, which
can drag down performance when all you
| | 00:45 | needed to do was get a default value.
| | 00:47 | Also, before the release of PHP 5.3,
the only way a developer could prevent a
| | 00:52 | function or variable from having
global scope was to declare it in a class.
| | 00:57 | Finally, there are circumstances when
you want to create only one instance of a
| | 01:00 | class, and share it across the application,
so it becomes important to be able to
| | 01:04 | limit instance creation.
| | 01:06 | To do this, we'll use the static keyword.
| | 01:09 | This makes the property or method
accessible without needing instantiation.
| | 01:13 | Static properties are unique in that
their values are stored at a class level,
| | 01:17 | not at an object's level.
| | 01:19 | This can be useful to keep track of
the number of instances, which I'll
| | 01:23 | demonstrate in a bit.
| | 01:25 | In the Address class, I want to
keep track of the different types of
| | 01:28 | addresses. For this demo, we'll keep
it simple with three address types,
| | 01:32 | each with a unique ID.
| | 01:34 | Let's use 1 for residence, 2
for a business, and 3 for a park.
| | 01:40 | We're going to assign labels to these
values, so we can display them to users,
| | 01:43 | and even use the values for validation.
| | 01:46 | As the address type is specific to
addresses, we'll associate it with a class.
| | 01:51 | By using the static keyword, we can
expose these address types to other parts of
| | 01:55 | the script without instantiation.
| | 01:58 | To declare a property static, we'll use
the same notation as we did with regular
| | 02:02 | properties, including scope.
| | 02:04 | The only difference is we'll add the
keyword "static" somewhere before the property name.
| | 02:08 | The order is actually flexible, but
it's best practice to stay consistent. I
| | 02:13 | prefer to start with static.
| | 02:15 | The declaration will end up looking
something like static public $variable = . . . and so forth.
| | 02:22 | Let's open the Address class. Then, I'm
going to add the following to the top.
| | 02:27 | Address types. static public $valid_
address_types = array, 1 is a residence, 2 is
| | 02:43 | a business, and 3 is a park.
Save, then open the demo file.
| | 02:55 | At the end, let's attempt to display
these address types. echo <h2>Displaying
| | 03:02 | Address types . . . echo <tt><pre> var_export,
($address->valid_address_types, TRUE),
| | 03:15 | Then close pre and tt.
Save then reload the browser.
| | 03:22 | Instead of the expected result, there
is an error message citing an undefined
| | 03:26 | property. This is due to the static keyword.
| | 03:30 | In the next video, I will describe how
to access a static property using a scope
| | 03:34 | resolution operator.
| | Collapse this transcript |
| Leveraging scope resolution operators| 00:00 | The scope resolution operator allows
access to static, constant, and overridden
| | 00:05 | properties and methods of a class
without needing to instantiate an object.
| | 00:09 | I'll cover constants in the next video,
and overwriting properties and methods
| | 00:13 | in the next chapter.
| | 00:14 | In the meantime, let's focus on
accessing the static address types.
| | 00:18 | The scope resolution operator in code
is just a double colon (::). To use this
| | 00:22 | token, you'll need the name of the class,
followed by the double colon (::). For a
| | 00:27 | method, just add the name of the
static method with parentheses, and whatever
| | 00:30 | arguments are needed. For a property, add
a dollar sign ($), then the name of the
| | 00:35 | static property that
you're going to be accessing.
| | 00:37 | Let's use the scope resolution
operator to access the static address types.
| | 00:42 | Now, let's switch back to the code,
replace the variable address with the class
| | 00:47 | name address, then replace the object
property access syntax symbols with a
| | 00:51 | double colon (::). Then finally, prepend
valid address types with a dollar sign ($).
| | 00:57 | Save the demo. Then, refresh the browser.
| | 01:00 | Instead of the error, you will see the
array of address types. Use of the scope
| | 01:04 | resolution operator is not limited to
accessing static properties and methods, as
| | 01:08 | I will demonstrate in the next video.
| | Collapse this transcript |
| Setting constant values| 00:00 | There's a strong possibility that
you're already familiar with constants.
| | 00:04 | They are common place in procedural code.
| | 00:06 | As a natural extension, it's possible to
add a constant to a class, which can be
| | 00:10 | good for code organization.
| | 00:13 | A class constant is like a property
with a value that never changes.
| | 00:17 | Constants are useful for defining things
like error codes, data structure names,
| | 00:21 | and values that have no need
to change at runtime, if ever.
| | 00:25 | By associating a constant with a class,
a developer can add context rather than
| | 00:30 | having to resort to long, complicated names.
| | 00:34 | While constants use the same PHP label
naming convention, best practice dictates
| | 00:38 | that constant names are all in
capital letters separated by underscores.
| | 00:43 | Constants can only contain simple values,
so strings, booleans and integers will
| | 00:48 | work, but an array will not.
| | 00:51 | To define a constant within a class,
start with the keyword "const," followed by the
| | 00:57 | name with no dollar sign ($), an
assignment operator, and a value.
| | 01:02 | Let's said add constant to the
address class to store the address type IDs.
| | 01:06 | I'm going to open the Address class,
and navigate to the top of the file, then
| | 01:12 | add three constants for each of
the address type values. const
| | 01:16 | ADDRESS_TYPE_RESIDENCE = 1, const
ADDRESS_TYPE_BUSSINESS = 2, and then const
| | 01:25 | ADDRESS_TYPE_PARK = 3.
| | 01:30 | Part of the reason why I did not
specify that the address types be defined as a
| | 01:34 | constant is that arrays are not allowed
as constant values. With that said, you
| | 01:39 | can replace the hardcoded values with
the constants that were just declared.
| | 01:44 | Similar to static properties, you use
the scope resolution operator to access
| | 01:48 | constants, only without the dollar sign ($).
| | 01:51 | Edit the static address types, and
replace the keys with the constant values.
| | 01:56 | Address::ADDRESS_TYPE_RESIDENCE,
Address::ADDRESS_TYPE_BUSSINESS and
| | 02:04 | Address::ADDRESS_TYPE_PARK and save.
| | 02:09 | There is no functional difference
between having the raw numbers there in the
| | 02:12 | constants, which is part of the goal.
| | 02:14 | The advantage is that there's only one
place where those values are set, which
| | 02:18 | makes them available to any other code.
| | 02:20 | I can refer it to these address type
IDs with semantic human readable names, as
| | 02:24 | opposed to trying to have to
remember what number is associated with them.
| | 02:28 | In a moment, I'll demonstrate how to
write a static method for validating address
| | 02:32 | type IDs using these class constants.
From a code maintainability perspective,
| | 02:36 | those constant values are now
available to any other piece of code, and can be
| | 02:41 | referenced using semantic names, as
opposed to trying to remember what number is
| | 02:45 | associated with which value.
| | Collapse this transcript |
| Implementing static methods| 00:00 | Static methods are similar to
regular methods in a number of ways.
| | 00:04 | The naming convention is the same, they
can have a visibility scope, and static
| | 00:08 | methods can return values.
| | 00:10 | However, static methods cannot use the
pseudo variable $this to get properties, as
| | 00:15 | it refers to the current object.
| | 00:17 | If you want to try anyway, you
can, but you will get a fatal error.
| | 00:20 | Instead, use the self keyword,
which refers to the current class.
| | 00:25 | This sounds a bit abstract,
| | 00:26 | so I'll demonstrate a static method by
implementing an address type id validator.
| | 00:31 | I'm going to open the Address class,
and then start declaring a static method.
| | 00:36 | Like static properties,
| | 00:37 | I'll need to include the static keyword.
| | 00:40 | Static public function
isValidAddressTypeId with one argument ($address_type_id).
| | 00:50 | Add the documentation, Determine if an
address type is valid. We'll take an
| | 01:03 | integer and return boolean.
| | 01:08 | To validate, check to see if the address
_type_id is in the array keys of valid
| | 01:13 | address types. return array_key_exists.
The key is the address_type_id. The array
| | 01:21 | will be self::$valid_address_types. Save,
then test the validator by opening the
| | 01:29 | demo script, navigating to the
end, and writing a quick test.
| | 01:36 | Start with the title, describing
what you're testing. echo <h2>Testing
| | 01:42 | address_type_ID validation.
| | 01:46 | Next, use a for loop to test
the whole numbers 0 through 4.
| | 01:50 | Start with a div, and display the
id. for ($id = 0; id <= 4; id++), echo
| | 02:01 | double quotes <div>$id is.
| | 02:07 | On the next line, use a ternary
operator to display whether the current id is
| | 02:11 | valid or invalid. echo Address::
IsValidAddressTypeId, Valid else Invalid. close
| | 02:25 | the div. Save the demo, and return to
the browser. Refresh to see the results.
| | 02:34 | Id 0 and 4 are invalid, while ID's 1,
2, and 3 are valid. Now that you have a
| | 02:40 | mechanism of validating an address type,
you can improve the Address class by
| | 02:45 | storing the address_type_id in the object,
but only allowing valid IDs to be stored.
| | 02:50 | Return to the Address class. Navigate
the properties. Then, add a new property
| | 02:59 | for address type id after the
address_id. protected address_type_id.
| | 03:09 | The next thing I'm going to do is
declare a new method for setting an
| | 03:13 | address_type_id in an address.
| | 03:15 | If I created it as a public method,
anything could set the address type, which I
| | 03:19 | don't want to allow.
| | 03:20 | Instead, I'll protect it, and use the
magic _get and _set methods to allow access.
| | 03:26 | Going back to the code, navigate to
the end of the file, and start declaring a
| | 03:30 | new function. protected function _
setAddressTypeId, which accepts one argument,
| | 03:40 | address_type_id, in the documentation.
If valid, set the address_type_id. And, the
| | 03:51 | parameter is an integer.
| | 03:54 | Next, check to see if the address
type is valid. You can also use the self
| | 03:58 | keyword, as the self keyword
refers to the class of the object.
| | 04:01 | if self::isvalidAddressTypeId. Set the
protected value. this->address_type_id
| | 04:13 | = $address_type_id.
| | 04:15 | Now that you have a way to set the
address_type_id, add the clue necessary for
| | 04:19 | public interface. The Magic _get method
needs no additional configuration, but
| | 04:24 | the _set method does. Navigate the Magic
_set method. Then, at the top, add an if
| | 04:31 | statement to check for the
property name address_type_id.
| | 04:35 | Only set valid address type id,
if address_type_id is == $name,
| | 04:45 | this->setAddressType value. Then
return. Save. Then return to the demo script,
| | 04:58 | navigate to the first creation of the
address object, and add an address_type_id,
| | 05:04 | to it. address->address_
type_id = 1. Save the demo.
| | 05:12 | Now return to your browser, and
refresh. Scroll up to the Setting property
| | 05:18 | section, and you will see
the newly set address_type_id.
| | 05:22 | We now have a way of validating user
input, and only setting good values.
| | 05:26 | By making the validator static, we can
use it outside of the address class.
| | 05:30 | This is useful for doing things
like validating form submissions.
| | 05:34 | The address class is growing nicely,
but there's still a placeholder for
| | 05:37 | the database lookup.
| | 05:39 | In a moment, I'll show you how to
connect to the database using a custom class.
| | Collapse this transcript |
| Creating a database class| 00:00 | Often it's optimal to only
connect to the database once.
| | 00:03 | I could connect and disconnect every
time I needed to query the database, but
| | 00:07 | that's hugely inefficient.
| | 00:09 | I could use a global variable assigned
to the connection, but that's fragile at
| | 00:13 | best, as anything could manipulate it.
| | 00:15 | It's better to control access, and
restrict the number of connections.
| | 00:18 | I am going to demonstrate how to
create a simple, but still useful class that
| | 00:22 | will only allow one
connection to the database at one time.
| | 00:26 | It'll provide access throughout the
application, and minimize the possibility for corruption.
| | 00:31 | To do that, I'm going to use the object-
oriented database connection from the
| | 00:35 | MySQLi improved extension (or MySQLi).
| | 00:39 | Create a new file in your Exercise
folder, and call it class_Database.inc.
| | 00:49 | Start a new class definition for the
database. And, add some documentation. Only
| | 01:00 | one connection is allowed.
| | 01:03 | The first property to create
will contain the connection.
| | 01:07 | Make it private, as the class
will be controlling access to it.
| | 01:11 | Next, make a private
static property called instance.
| | 01:15 | Remember, static properties can be
changed after being defined, and the value is
| | 01:20 | stored at the class level.
| | 01:22 | private static $_instance.
| | 01:29 | Provide a public static method to
allow any part of the program to access
| | 01:33 | the database instance.
| | 01:35 | public static function getInstance.
| | 01:39 | If the instance does not exist, create
it using self, only as a function call.
| | 01:45 | if not self instance, self
::$_instance = new self.
| | 01:56 | Then, return the static instance.
| | 01:58 | return self::$_instance.
| | 02:02 | Add proper documentation, get an instance
of the database, and return type database.
| | 02:14 | Now, define the
constructor for the database object.
| | 02:20 | public function __construct.
| | 02:24 | Start the constructor
with a new MySQLi connection.
| | 02:28 | The arguments are in the following order:
| | 02:30 | host, username, password, and database name.
| | 02:35 | As your environment may be different
from mine, take note of your connection
| | 02:39 | details, and replace as necessary.
| | 02:42 | Error handling, if mysqli_connect_
error, then trigger error (failed to connect
| | 02:54 | to MySQL, followed by my mysqli_connect_
error(), and we'll set the level as E_USER_ERROR;.
| | 03:10 | I want to prevent the database
connection from getting copied, so I'll use the
| | 03:14 | magic method clone, which
specifies how an object is duplicated.
| | 03:18 | I'll get into object cloning a bit
later on, but for now, I'll just define an
| | 03:22 | empty clone magic method, which will do
nothing, including no copying, which is
| | 03:26 | exactly what I want.
| | 03:28 | Empty clone magic method to prevent
duplication, private function __clone, and
| | 03:39 | two curly braces ({}).
| | 03:41 | Finally, define a public method
for getting the MySQLi connection.
| | 03:45 | Get the MySQLi connection.
| | 03:50 | Public function getConnection.
return $this->_connection. Save the file.
| | 04:02 | Now that a database connection is
available, let's go back to the Address class,
| | 04:06 | and get rid of the
placeholder postal code lookup.
| | 04:09 | Navigate to _postal_code_
guess, and replace the contents.
| | 04:15 | First, get an instance of the database.
| | 04:22 | Next, get the connection.
| | 04:28 | Write the SQL query.
| | 04:30 | You'll want to get the postal code
from the location table on the database,
| | 04:33 | which is provided in the Exercise Files.
| | 04:38 | SELECT postal_code from location.
| | 04:46 | Escape the variables, as the biggest
danger to your application is user input.
| | 04:51 | city_name is mysqli->real_escape_string ($
this->city_name); WHERE city_name = $city_name.
| | 05:10 | We'll do the same for the
subdivision name. $this->subdivision_name; AND
| | 05:27 | subdivision_name = execute the
query that you have created. $result =
| | 05:37 | mysqli->query($sql_query).
| | 05:46 | If there was a match, we
turn the postal code if ($row =
| | 05:50 | $result->fetch_associative
array, return $row 'postal code'.
| | 05:59 | Save the Address class,
then return to the demo file.
| | 06:03 | As we've created a new database
class, required at the top. require
| | 06:07 | 'class.Database.inc.
| | 06:12 | This file has gotten a bit long with
all the testing, so let's simplify a bit.
| | 06:16 | Remove the empty address.
| | 06:19 | Next, unset the postal code in the
first address to test the new lookup.
| | 06:24 | Then, replace the var export, and
display after setting the address properties
| | 06:28 | with an echo address, using
the two-string magic method.
| | 06:35 | Remove the Testing magic __get and __set.
| | 06:37 | In the second address, remove the postal
code, then replace the explicit call to
| | 06:42 | display with echo $address_2.
| | 06:44 | We don't need to debug the address types
anymore, so they can be safely removed.
| | 06:50 | Save the demo, then return
to the browser, and refresh.
| | 06:54 | I can see that the postal codes are
still being displayed, but now they're
| | 06:58 | coming from the database.
| | 07:00 | In this chapter, we accessed
classes without instantiation.
| | 07:04 | First, I discussed how
to use the static keyword.
| | 07:07 | I used the scope resolution operator
to access static properties and methods.
| | 07:11 | I demonstrated how to set constant
values in the class, which never change, then
| | 07:15 | implemented a static method
to validate address type IDs.
| | 07:19 | Finally, I created the database class
to only allow one connection at a time.
| | 07:24 | With this foundation and ability to
control access to resources, you have the
| | 07:28 | beginnings of a stable and robust
system, logically-structured and named.
| | 07:32 | In the next chapter, I'll add
further structure and hierarchy using
| | 07:35 | class relationships.
| | Collapse this transcript |
|
|
5. Class Relationships and InteractionsExtending your class| 00:00 | In this chapter, I'm going to
introduce class hierarchies.
| | 00:04 | First, I'm going to demonstrate how
classes can relate to one another. Then I'll
| | 00:08 | show how to create
blueprints for classes and methods.
| | 00:11 | We'll make unified
interfaces with polymorphic behaviors.
| | 00:15 | I'll demonstrate how to override
methods, properties, and even constants.
| | 00:20 | We'll copy and compare objects, then
finally explore ways that objects can be
| | 00:24 | manipulated indirectly.
| | 00:26 | Before we go any further, I'd like to
teach you a neat way of dealing with large
| | 00:30 | numbers of class files gracefully.
| | 00:32 | Currently in the demo file, we're
explicitly requiring both the address and
| | 00:36 | the database class.
| | 00:37 | However, as we add more classes with one
file per class, things are going to get
| | 00:42 | a bit messy with more requires.
| | 00:44 | Good thing there is another option. As of
PHP 5, a new solution was added, known as
| | 00:49 | Autoloading classes.
| | 00:51 | If you define an autoload function, it
will automatically be called whenever you
| | 00:55 | try to access a class that hasn't
been defined yet, kind of like a failsafe
| | 00:59 | before PHP gives up, and has a fatal error.
| | 01:02 | I am going to replace the two require
statements at the top of the demo with
| | 01:06 | an autoload function definition.
function __autoload, which takes one argument.
| | 01:13 | $class_name. include anything that
starts with 'class.' and then the
| | 01:20 | class_name.inc. Define autoloader with one
parameter string $class_name. Save the file.
| | 01:35 | Now that we future-proofed the
application, let's discuss inheritance.
| | 01:40 | Inheritance is a core object-oriented
principle, where relationship between
| | 01:44 | classes can be established.
| | 01:46 | Think of it as a parent and child
relationship, where the parent is a class, and
| | 01:51 | a child is a subclass of the parent.
| | 01:54 | The child inherits all of the parent's
behaviors and properties, making it an
| | 01:57 | inclusive superset of
both the child and the parent.
| | 02:01 | There are a number of
characteristics of inheritance that are useful.
| | 02:05 | Both the parent and the child share
common functionality, without having to
| | 02:08 | copy and paste code.
| | 02:10 | The child can have new functionality
that the parent does not. Therefore, the
| | 02:14 | child extends the parent,
which is also the key word used.
| | 02:18 | The only way that a child can extend a
parent is if the parent has been declared.
| | 02:23 | Classes can extend only one class's
methods and properties at a time. You can't
| | 02:27 | specify multiple classes to extend.
| | 02:30 | You can, on the other hand, extend a
class that extends another class.
| | 02:34 | You just can't extend
two classes simultaneously.
| | 02:37 | This is a lot to think about,
so let's see it in action.
| | 02:41 | In the previous chapter, we added a
property to the address class to track what
| | 02:45 | type of an address an object was:
| | 02:47 | a residence, business, or park.
| | 02:50 | I want to avoid code duplication, but still
be able to add address type specific behavior.
| | 02:55 | Therefore, I'll make address a parent
class, and make child classes for the
| | 02:59 | three address types.
| | 03:01 | We'll implement unique
behaviors in the next segment.
| | 03:04 | I'm going to switch back to the IDE.
| | 03:07 | In the previous chapter, you added a
property to the Address class to track what
| | 03:11 | type of an address an object was:
| | 03:13 | a residence, business or park.
| | 03:16 | For this exercise, I'm going to assign a
different behavior to each address type.
| | 03:21 | You'll implement that behavior in the next
video, but to do so, you'll need a place to put it.
| | 03:27 | Start the class definition with the
name of the class, followed by the keyword
| | 03:31 | extends, then the name of
the class you are extending.
| | 03:34 | PHP label conventions apply to the
name of the class, but best practice is to
| | 03:38 | start with the name of
the class you are extending.
| | 03:41 | Create a new file in your Exercise
folder called class.AddressResidence.inc.
| | 03:47 | Start the class definition with the
name of the class, followed by the keyword
| | 03:51 | extends, then the name of
the class you're extending.
| | 03:54 | PHP label conventions apply to the
name of the class, but the best practice
| | 03:58 | is to start with the name of the class you're
extending. class AddressResidence extends Address.
| | 04:10 | Add quick documentation, and save.
That's all that needs to be added for now as
| | 04:18 | different behavior will be defined later.
| | 04:20 | Next, create a new file for the
business address called class.AddressBusiness.
| | 04:29 | The contents will be virtually identical. Save,
| | 04:39 | then create the final file for a
park address. class.AddressPark.inc.
| | 04:54 | And then, class.AddressPark extends Address.
| | 04:58 | Save, and return to the demo file.
Following the autoloader, change the title
| | 05:04 | to AddressResidence.
| | 05:08 | Address is new AddressResidence.
And, re-factor the remaining code.
| | 05:21 | Add debugging to display the contents
of the address_residence variable. echo
| | 05:27 | <tt><pre> var_export{$address_
residence, TRUE} close pre, close tt.
| | 05:39 | Save, then switch to your browser.
| | 05:43 | When you refresh the page, you will see
that the class is now address_residence,
| | 05:47 | and that all the functionality that you
previously defined in the Address class
| | 05:50 | still works, and is still
accessed in the same manner.
| | 05:53 | Also note that the second address,
which is just class address, functions as it
| | 05:58 | was before, even as a parent.
| | 06:01 | In the next video, I'll demonstrate how
to prevent the use of the parent address,
| | 06:05 | and how to add custom
behaviors to the child classes.
| | Collapse this transcript |
| Abstracting classes| 00:00 | Visibility scope is not the only
object-oriented way to restrict access.
| | 00:04 | PHP5 also introduced the concept
of abstract classes and methods.
| | 00:09 | If a class is defined as
abstract, it cannot be instantiated.
| | 00:14 | If you define a method as abstract,
then any class that extends that
| | 00:18 | abstract class containing the method
must also declare a method with the
| | 00:22 | same name and arguments.
| | 00:24 | Further, if a class has an abstract method,
then the class itself must be abstract.
| | 00:30 | This solves the problem of the generic
address class, and provides a mechanism to
| | 00:34 | specify the behavior of any child classes.
| | 00:38 | Open the address class, scroll to the
top, and add the word "abstract" at the
| | 00:43 | beginning of the class declaration.
| | 00:45 | Save the address, then switch to
your browser, and refresh the demo.
| | 00:50 | At the bottom, the attempted
instantiation of the generic address class has been
| | 00:54 | disallowed, and caused a fatal error.
| | 00:56 | This is a good thing, as it
forces the developer to be specific.
| | 01:00 | Edit the demo, and re-factor the second
address instance to be a business address,
| | 01:04 | including the variable name.
AddressBusiness. address_business for the variable
| | 01:13 | name as well. And then, add a var_
export at the end, so we can inspect the
| | 01:22 | contents. Save the demo, go
back to the browser, and refresh.
| | 01:28 | The business address is now displayed correctly.
| | 01:31 | However, there is a data inconsistency;
it's the correct class (AddressBusiness),
| | 01:36 | but the _address_type_id is not set.
| | 01:40 | Missing property values is a
common development problem.
| | 01:43 | When working with multiple similar
objects, there can be a lot of easily
| | 01:47 | forgotten details to keep track of.
| | 01:49 | The solution is to initialize
objects automatically, so you don't have to
| | 01:53 | remember to do it, but what's
the best way to initialize them?
| | 01:57 | Your first reaction may be to make the
construct magic method abstract. This
| | 02:01 | would technically work, but you'd end up
with a lot of copied and pasted code, as
| | 02:06 | everything in construct
would have to be duplicated.
| | 02:09 | This can easily lead to a fragile
system, where re-factoring or adding new
| | 02:13 | functionality becomes cumbersome.
| | 02:15 | It's not a best practice,
and not very object-oriented.
| | 02:19 | Instead, I'm going to construct
the object in the parent, then call an
| | 02:22 | abstract initializer.
| | 02:24 | This way, common behavior in the
parent's construct method always executes upon
| | 02:28 | instantiation. Then, custom
behavior can be put in each child's
| | 02:32 | initialization method. Neat!
| | 02:35 | With these relationships, visibility
is also a factor, and abstract method
| | 02:39 | visibility can be a bit tricky.
| | 02:41 | Methods that implement an abstract
method will also need to have the same scope,
| | 02:46 | or something a little bit less restrictive.
| | 02:48 | If an abstract method is declared as public,
I won't be able to change it to private.
| | 02:53 | However, the opposite is true.
| | 02:56 | I can make an abstract private method public.
| | 02:59 | It's a one-way change.
| | 03:01 | You can relax the scope
restriction, but not make it stricter.
| | 03:05 | This prevents a situation when you're
expecting to be able to do something, but
| | 03:08 | for some strange reason, you are prevented by scope.
| | 03:11 | To practically apply this to the
addresses, I'm going to require that extending
| | 03:15 | classes set the address type id upon creation.
| | 03:19 | Let's open the Address class.
| | 03:21 | After the magic method toString, define
a new abstract protected method called
| | 03:27 | init, abstract protected function _init().
| | 03:36 | Force extending classes to implement
init method, then add a call to the
| | 03:44 | initialization method at the beginning
of the constructor. $this->init. Save the
| | 03:53 | address class, then go to
your browser, and refresh.
| | 03:58 | You will see an immediate error.
| | 03:59 | The AddressResidence class contains an
abstract method that needs to be defined.
| | 04:04 | So, open the AddressResidence class, and
declare the private function initialized.
| | 04:09 | protected function _init(). Set the
address type id to the constant from the
| | 04:15 | address class, using your validating method:
| | 04:18 | $this->
setAddressTypeIDAddress::ADDRESS_TYPE_RESIDENCE.
| | 04:27 | Add some documentation, and copy the
contents of this method, and paste it into
| | 04:39 | the business address. ADDRESS_TYPE_
BUSINESS. And, again for the Park. Save, then
| | 04:52 | return to your browser, and refresh.
| | 04:55 | You'll see that the _address_type_id
for the business is now set correctly.
| | 04:59 | However, a redundancy has now been
introduced with the potential for corruption.
| | 05:04 | You can still set the _address_type_
id manually, and if you look at the demo,
| | 05:08 | AddressResidence is doing just that.
| | 05:12 | You can just remove the _address_type_id,
but that treats the symptom, not the problem.
| | 05:16 | Return to the address class, and
navigate to the magic set method.
| | 05:20 | Remove the special case for _address_
type_id. Save, then refresh the demo.
| | 05:28 | You will see a notice for
undefined or unallowed property.
| | 05:31 | Data corruption is now prevented.
| | 05:33 | Edit the demo, and remove the now-
broken attempt to set the _address_type_id.
| | 05:39 | Then save, and refresh.
| | 05:43 | The notice is now gone,
and execution is error-free.
| | 05:47 | In the next segment, I'm going to
demonstrate how to implement a common
| | 05:50 | interface across all these child
address classes without having to know what
| | 05:54 | kind of an address type it is.
| | Collapse this transcript |
| Sharing interfaces using polymorphism| 00:00 | When developing an application, I'm
typically working with many different kinds
| | 00:04 | of data in different structures,
each with a different behavior and need.
| | 00:08 | However, if I were to use
different naming conventions for every single
| | 00:11 | data structure, my
application would descend into chaos!
| | 00:15 | The phrase "Spaghetti code" is an apt
description, meaning the source code is
| | 00:19 | impossibly complex and
tangled, like a pile of pasta.
| | 00:22 | Sounds delicious, but
it's difficult to organize.
| | 00:26 | To avoid this mess, I can use an
object interface. An interface specifies
| | 00:31 | what methods a class must implement,
but doesn't say how those methods
| | 00:35 | should be implemented.
| | 00:36 | There are similarities to an abstract
class, but the main importance is that
| | 00:40 | interfaces don't have any methods of their own.
| | 00:43 | In fact, an interface is not a class at
all, but it's similar enough that auto
| | 00:47 | loading will work with it.
| | 00:49 | To use an interface, a class uses
the keyword implements, followed by the
| | 00:54 | name of the interface.
| | 00:55 | A class can implement more than one
interface at a time by separating their
| | 00:59 | names with a comma, as long as those
interfaces don't have conflicting method names.
| | 01:04 | Interfaces can also have constants, which will
be available to any classes that implement it.
| | 01:09 | Interface constants cannot
be overridden or defined.
| | 01:13 | Overwriting is going to be covered
in greater detail in the next segment.
| | 01:16 | So, what's the point of all this?
| | 01:18 | Well, the practice of sharing a common
application programming interface, or API,
| | 01:23 | between classes is known as
polymorphism. And, interfaces fit that definition
| | 01:28 | quite well, because they're
designed exactly for that purpose.
| | 01:32 | In our application, I'm going to define
an interface that both the address class
| | 01:36 | and future classes must implement.
| | 01:38 | When designing an interface, try to be
as generic as possible, yet still kind of
| | 01:43 | specific enough to be useful.
| | 01:44 | That sounds like a hard line to walk.
| | 01:46 | So, to demonstrate this, I
am going to create a model.
| | 01:49 | A model is responsible for managing
data, and storing and retrieving entities,
| | 01:53 | and containing business logic.
| | 01:55 | This aptly describes what the address
class is going to be doing at a high level,
| | 01:59 | and applies to future classes as well.
| | 02:02 | I am going to the switch to the IDE.
| | 02:04 | Let's create a new file called Class.Model.Inc.
| | 02:09 | Start with the keyword interface, followed by
the name. Shared interface for interactions.
| | 02:18 | I am going to require two
methods in this interface.
| | 02:22 | The first is Load, which will load
from the database, given an address ID.
| | 02:26 | I am using Static, as I can't guess
what type of address will be returned, so
| | 02:31 | I'll add logic that will
return the correct address subclass.
| | 02:35 | The second method will be Save, which
will just save to the database. static
| | 02:40 | function load, which takes an
address_id. Load a model. param int
| | 02:50 | $address_id. Next, function save, which will save
a model. Save, then switch to the Address class.
| | 03:02 | You want to make the Address class
implement the new model interface.
| | 03:05 | So, after the name of the class,
add the following: implements Model.
| | 03:13 | If I were to save and refresh the demo,
I'd get a fatal error, because the address
| | 03:17 | class doesn't declare the
methods from the model interface.
| | 03:20 | We are setting up a situation where
there's the possibility that a childs
| | 03:24 | class can potentially declare a method
that's already in the parent, like Load or Save.
| | 03:29 | This is known as an override.
| | 03:31 | I don't want to let that happen.
| | 03:32 | So, I'm going to use the keyword Final.
| | 03:35 | When used on a method, Final prevents
childs classes from overwriting the method.
| | 03:39 | So, only the parent address
class can describe the save behavior.
| | 03:43 | I can also declare a class as Final,
which will keep it from being extended.
| | 03:47 | I'm going to make the Load and Save
methods in the address class Final.
| | 03:51 | At the end of the address class, add a
final public static function load, which
| | 03:58 | accepts an address_id, placeholder,
followed by a final public function save.
| | 04:09 | Add documentation. param as an integer.
And, add documentation. save the address.
| | 04:24 | For now, I'm going to leave the
declarations empty, and leave them for a later segment.
| | 04:29 | With the introduction of the final
keyword, I mentioned overrides, but didn't
| | 04:32 | go into much detail.
| | 04:34 | In the next segment, I'll
discuss how to override methods,
| | 04:37 | properties, and constants.
| | Collapse this transcript |
| Overriding methods, properties, and constants| 00:00 | Sometimes, it's useful to be able
to change how a child class works.
| | 00:04 | To do that, I'll use an override
which is just re-declaring a method,
| | 00:08 | property, or constant.
| | 00:10 | If I was to override a property in a
child class, I would just declare the
| | 00:14 | property with the same name in the child.
| | 00:16 | Visibility and overrides are similar
to abstraction in that I can change the
| | 00:20 | visibility scope, but I can't make it stricter.
| | 00:23 | Overriding a property is very straightforward.
| | 00:26 | In the child class, declare the property.
| | 00:29 | As a demonstration, open the PARK class,
then override the country name with the
| | 00:33 | default, Australia.
public $country_name = Australia.
| | 00:41 | Save, then open the demo script.
| | 00:45 | At the end, add the following: echo <h2>
Instantiating AddressPark, $address_park
| | 00:57 | = new AddressParkarray street_
address_1 => 789 Missing Circle;
| | 01:14 | street_address_2 => suite 0, city_name =>
Hamlet, in subdivision_name => Territory.
| | 01:32 | We'll echo $address_park, display it, and then
debug it. Save, then refresh your browser.
| | 01:50 | You'll see that the country is Australia.
Return to the PARK class, and remove
| | 01:54 | the property override, then save. Add
the country name to the demo, AddressPark.
| | 02:03 | Overriding a constant is very similar to
overriding a property. Just re-declare it.
| | 02:08 | There is one restriction.
| | 02:09 | I can't re-declare a constant that was
declared in an interface. Because it's so
| | 02:13 | similar, I'm not going to
demo overriding a constant.
| | 02:16 | Overriding methods, on the
other hand, has some unique quirks.
| | 02:20 | The new method must have the same
number of arguments as the overridden method.
| | 02:24 | There is an exception with constructors,
where you can re-declare more or less arguments.
| | 02:29 | Overriding methods can also access
methods and properties from the parent class.
| | 02:33 | This is very good for defining a child's
behavior before and after a parent's behavior.
| | 02:38 | As an example of this, I'll
demonstrate a method override on the PARK class
| | 02:42 | display to give it a green background.
| | 02:44 | Let's open the AddressPark class, and
declare a new display method. public
| | 02:49 | function display. output = div with
the style of background-color:PaleGreen.
| | 03:01 | Use the keyword parent as the class
name to reference the parent of the
| | 03:04 | extended class address.
| | 03:06 | I'll put parent::display, close the div,
and return the output. Save, then return
| | 03:17 | to the browser, and refresh.
The park address is now green.
| | 03:20 | Next, I will demonstrate how
to copy and compare objects.
| | Collapse this transcript |
| Cloning and comparing objects| 00:00 | Sometimes, you will want to
make a copy of an object.
| | 00:03 | There are many reasons to do this,
including making a backup before performing an
| | 00:07 | operation, or as a shortcut
for defining a similar object.
| | 00:10 | To create a copy of an object, use the
clone keyword. As a demonstration, make a
| | 00:15 | copy of the park address, open the demo
script, and navigate to the bottom. Add
| | 00:21 | the following lines:
| | 00:22 | echo <h2>Cloning AddressPark</h2>
$address_park_clone = clone $address_park. And
| | 00:37 | then, we'll debug the clone.
| | 00:41 | To check the differences between
clones, I'm going to compare two objects.
| | 00:45 | Comparing objects is a lot like
comparing primitives, such as strings and floats.
| | 00:50 | I can use the comparison operator, double
equals (==), which will check to see if
| | 00:54 | the properties are the same.
| | 00:56 | If I need to be more strict, I can
use the identity operator, triple equals
| | 01:00 | (===), to also check if both
objects are instances of the same class.
| | 01:05 | At the end of the script, add echo $
address_park_clone_ is. And then, a ternary
| | 01:14 | statement. $address_park
== $address_park_clone ? :
| | 01:23 | not ] a copy of $address_park. Save
the demo, and refresh the browser.
| | 01:35 | Visually, every property is the same,
and the final line indicates this.
| | 01:40 | However, the time created isn't
necessarily the same, especially if one object is
| | 01:45 | based on an old record from the database.
| | 01:47 | To deal with this, I'm going to use the _
clone() magic method in the address class.
| | 01:52 | If the method exists, it will
be called after object cloning.
| | 01:56 | As an example, I am going to use
this to reset the time created.
| | 01:59 | Let's go back to the address class.
Then, after the properties, add the clone
| | 02:04 | method, which takes no arguments.
Remember to add proper documentation.
| | 02:15 | For the demonstration, I will
explicitly set the time_created and time_updated
| | 02:19 | to obvious values. Save, then
switch to the browser, and refresh.
| | 02:24 | The time_updated and created have been
set to the new values, and the final line
| | 02:28 | states that $address_park_clone is not
a copy of $address_park. Return to the
| | 02:32 | clone function, and set time_
created = time, and time_updated = Null.
| | 02:40 | Now that I've demonstrated object
cloning, I am going to discuss how
| | 02:44 | to reference objects.
| | 02:45 | Referencing can be similar to cloning,
but there are enough differences to make
| | 02:49 | it worth exploring on its own.
| | Collapse this transcript |
| Referencing objects| 00:00 | In PHP, a reference is an alias, meaning two
different variables can write to the same value.
| | 00:06 | There is a good chance you've
seen this in procedural code before.
| | 00:09 | Referenced objects are a bit different
however, in that the object variables do
| | 00:13 | not contain the actual object itself,
only the internal object identifier, which
| | 00:18 | is behind the scenes in PHP.
| | 00:20 | This is one of the major changes from
PHP 4, which greatly improved memory
| | 00:24 | usage and performance.
| | 00:26 | To demonstrate this, make a copy
of the variable for AddressBusiness.
| | 00:29 | Add the following block to the end of
the demo: echo <h2>Copying AddressBusiness
| | 00:37 | reference; $address_business
_copy = $address_business.
| | 00:45 | Copy the logic from the last demo.
| | 00:47 | Use triple equals (===) to
determine if it's an exact copy.
| | 00:51 | address_business_copy is or is
not a copy of address_business.
| | 01:00 | Next, we're going to set address_
business_copy as a new address_park. echo <h2>
| | 01:06 | setting_address_business as a new
address_park. $address_business = new
| | 01:17 | address_park. And, we'll paste the same line.
| | 01:24 | Finally, use the get_class function to
get the name of an object's class. echo
| | 01:28 | '<br/>$address_business is class
' . get_class($address_business).
| | 01:40 | You can also use the function
instanceof to make logical decisions.
| | 01:45 | echo '<br/> address business copy
is address_business_copy instanceof
| | 01:58 | AddressBusiness and $address_business.
| | 02:07 | This last line will determine
whether or not address_business_copy is an
| | 02:10 | instance of address_business.
| | 02:12 | Save, and view the result in your browser.
| | 02:18 | When you copy by identifier, you end up
with a copy of the object, as you would expect.
| | 02:23 | To demonstrate this, I am
going to make a copy by reference.
| | 02:26 | Return to the demo code, and add the
reference symbol to the assignment, after
| | 02:30 | address_business_copy.
| | 02:31 | Save, and rerun the demo.
| | 02:34 | This time, the object comparison makes
it clear that actions taken on the core
| | 02:38 | object affect the referenced object.
| | 02:41 | In this chapter, the focus has been on
class relationships and interactions.
| | 02:45 | We started by extending the Address
class with address type specific subclasses,
| | 02:49 | and enabled autoloading to deal
with all the different class files.
| | 02:53 | We then abstracted the Address class
and methods, and then created a shared
| | 02:56 | interface to add structure.
| | 02:58 | We overrode methods and properties, and
learned how to override constants, as well.
| | 03:03 | We made copies of objects, and
compared them to one another, and
| | 03:06 | implemented cloning behaviors.
| | 03:08 | Finally, we experimented
with referencing objects.
| | 03:11 | In the next chapter, I'm going to
demonstrate objects that are ready built into
| | 03:15 | PHP, including the
standard class and exceptions.
| | Collapse this transcript |
|
|
6. Built-In PHP ObjectsLeveraging standard class objects| 00:00 | In this chapter, I'm going to
explore built-in PHP objects.
| | 00:04 | I'll start with the standard
class, which is pretty generic,
| | 00:07 | then demonstrate how to
get objects from the database.
| | 00:10 | We'll handle errors in an object-oriented
way, then customize them to meet our needs.
| | 00:14 | Let's start with the standard class.
| | 00:16 | A standard class is a generic class
that can be created by typecasting a value
| | 00:20 | as an object, like casting the
string "hello, world" as an object.
| | 00:24 | It won't have any methods,
but it will have values.
| | 00:27 | In case you were wondering, if you
typecast an object to an object, that's kind of
| | 00:31 | goofy, and nothing will happen.
| | 00:34 | If you typecast that array to an
object, the result will be an object with
| | 00:37 | properties named for the keys to the array,
with values corresponding to the array values.
| | 00:43 | Let's clean up the demo,
and remove the cloning tests.
| | 00:46 | Create a test standard class
object out of a nested array.
| | 00:51 | Echo <h2> Testing typecasting to an object>.
| | 01:01 | $test_object = (object). This is the
typecasting. array. hello as the key and
| | 01:10 | world as the value. Then
nested as an array ( 'key => value').
| | 01:24 | Then, debug the test object.
| | 01:29 | Save, then refresh your browser.
| | 01:33 | The result will be a standard class with
properties "hello" and "nested," with nested
| | 01:37 | containing an array.
| | 01:39 | If I was to typecast any other data
type like a string, the value would be
| | 01:43 | converted to a standard object,
with one property named scalar.
| | 01:47 | Return to the demo, and replace the array
definition with the number 12345. Save, and refresh.
| | 02:00 | The test object now has one
property, scalar, with the value 12345.
| | 02:07 | Standard class objects are
practically used in a number of ways.
| | 02:10 | For example, returning a defined data
structure with fixed branches without nesting.
| | 02:16 | Sometimes, it's used as a shorthand to
speed code development, as it takes less
| | 02:20 | characters to access a property
than it does to specify a key.
| | 02:24 | Finally, you can use a standard object
when interacting with a method that is
| | 02:28 | looking for an object with
particular properties, but isn't actually
| | 02:31 | checking for the class.
| | 02:33 | In the next video, I will show you
how to load objects directly from the
| | 02:37 | database, then intelligently load
addresses from the database into the
| | 02:40 | correct class.
| | Collapse this transcript |
| Retrieving objects from the database| 00:00 | I can also create a standard
object straight from the database.
| | 00:04 | One of the methods in MySQLi, fetch_
object, returns the current row of a result
| | 00:09 | set as a standard class object.
| | 00:11 | Let's add this to the address model.
| | 00:13 | Let's go to the load
function, which is currently a stub.
| | 00:16 | I am going to add a connection to
the database. Connect to the database,
| | 00:28 | then write the query to retrieve a row from
the address table by the primary key, address_id.
| | 00:34 | For safety, I'm using quotations
around the identifier, and casting the
| | 00:38 | identifier as an integer. sql_query
equals SELECT everything from address, from
| | 00:51 | address where address_id
equals (int) $address_id.
| | 01:05 | The $result = mysqli ->query($sql_query).
| | 01:13 | Use the mysqli result object to
fetch an object from the database.
| | 01:18 | If ($row = $result -> fetch_object.
Display the row, then exit var_dump ($row) exit.
| | 01:32 | Save, then open the demo script.
| | 01:37 | Remove the test object code, then add
a title section for testing loading,
| | 01:41 | followed by a call to the static
method load in the address class.
| | 01:45 | There is one test row in the address
table, so explicitly load using the first
| | 01:48 | row. echo <h2>Loading from database,
$address_db = Address:(1). Then, debug the
| | 02:08 | address_db variable.
| | 02:11 | Save, then switch to the browser, and reload.
| | 02:18 | The object returned from the
database is a standard object.
| | 02:21 | MYSQLI can also populate objects if
you pass the object name as a parameter.
| | 02:27 | But as there is potentially data for
multiple classes in this one table, you
| | 02:31 | will not be able to use that. Instead
switch MYSQLI's fetch to an associative
| | 02:36 | array. fetch_assoc.
| | 02:43 | In order to automatically populate
address objects, I'm going to define a public
| | 02:47 | static helper method. It will get an
instance of a particular class based on the
| | 02:52 | address type ID, then populate it with an array.
| | 02:55 | I'll make it public, as I can reuse
this method elsewhere, as it's useful to
| | 02:59 | be able to create addresses
without having to explicitly specify the
| | 03:02 | subclass. final public static
function getInstance starts with an address
| | 03:14 | type_id, and takes data, which is an
array. Add documentation, given an address
| | 03:26 | type_id. Return an instance of that
subclass param int $address type_id
| | 03:34 | @param array $data, and then return
address, and it will add a note that it
| | 03:42 | will be the sub class.
| | 03:44 | As all the address classes start with the
address, start the class name with the address.
| | 03:50 | Then, using the static property
containing the array of address types, get the
| | 03:54 | name of the type of address.
| | 03:59 | $class_name equals address, followed by self::
valid_address_types [$address_type_id];
| | 04:10 | You can use the new keyword with a
variable name. Just follow it with
| | 04:13 | parentheses containing the data for the
constructor. Return new $class_name. And,
| | 04:22 | we'll pass the data.
| | 04:24 | Now that you have a mechanism to
return a class of any address type, return
| | 04:28 | to the load method.
| | 04:30 | Instead of dumping the contents and
exiting, call the getInstance method.
| | 04:34 | Remember, you can't use this in a
static context. Return self::getInstance ($row
| | 04:47 | ['address type id'], followed
by the whole row itself.
| | 04:54 | Before testing this out, a small
change needs to be made to the constructor.
| | 04:59 | When it was initially written, it
supported the protected properties, time
| | 05:02 | created and time updated.
| | 05:04 | Since that point, additional protected
properties were added, but the constructor
| | 05:08 | did not account for them, as there were
no records coming from the database yet.
| | 05:11 | Then add two new lines. address_id and
address type_id. These will be prepended
| | 05:21 | with an underscore for the protected properties.
| | 05:24 | Save, then go to your
browser, and refresh the page.
| | 05:30 | The loader and helper functions have
chosen the correct class for the row.
| | 05:34 | In the next video, I will demonstrate
how to intentionally create and respond to
| | 05:38 | object-oriented errors in PHP.
| | Collapse this transcript |
| Error handling with exceptions| 00:00 | Exception handling is an object-
oriented way of responding to abnormal or
| | 00:04 | exceptional situations
that can change program flow.
| | 00:07 | Practically speaking, this
means avoiding crashing.
| | 00:10 | When there is serious fault, PHP
creates what's known as an exception, which is
| | 00:14 | a problem that needs to be dealt with.
| | 00:16 | When an exception is created, it's
thrown, which is kind of like telling
| | 00:20 | everybody that there is a problem.
| | 00:22 | To handle an exception, somebody must
catch it, which means someone is listening,
| | 00:26 | and dealt with the problem.
| | 00:28 | To prepare for this, I need to
surround the code that can throw an exception
| | 00:31 | with a try block, followed by a catch.
| | 00:34 | This is like me saying, "Let me try to do
this action, and if it doesn't work, then
| | 00:39 | I'll deal with the problem."
| | 00:40 | If an exception is thrown and not
caught, the program crashes. Not cool.
| | 00:46 | Exceptions are good, as they are a much
nicer and logical way of dealing with problems.
| | 00:50 | Instead of just stopping or displaying
an error, I've got a chance to gracefully
| | 00:55 | recover, and do something else.
| | 00:57 | I can intentionally throw an
exception as well, which is good if a program
| | 01:00 | requires something that is missing, or
custom code is out of logical bounds.
| | 01:05 | To throw an exception, use the throw
keyword followed by new, then the Exception class.
| | 01:11 | Within the address example, there are
several opportunities to throw an exception.
| | 01:15 | An obvious place to start would be
the attempt to load from the database.
| | 01:19 | If a row is not found, then throw an exception.
| | 01:23 | Open the Address class, and
navigate to the load method.
| | 01:28 | Following the if, there is a row check.
| | 01:31 | Throw a new exception stating the problem.
| | 01:34 | The first argument is the message.
| | 01:36 | throw new Exception ('Address_not_found'). Save,
| | 01:43 | then edit the demo.
| | 01:47 | Instead of loading address id 1, attempt
to load address id 0, which does not exist.
| | 01:53 | Save, then switch to the browser, and refresh.
| | 01:57 | You will see an uncaught exception.
| | 01:59 | In the next video, I will demonstrate
how to catch this exception, then how to
| | 02:03 | customize exceptions to meet your needs.
| | Collapse this transcript |
| Customizing PHP exceptions| 00:00 | In the previous segment, we threw an
exception, because of an unknown address ID,
| | 00:04 | but didn't catch it, which
resulted in a fatal error.
| | 00:07 | Let's make the demo more resilient, and
deal with this unfortunate circumstance
| | 00:11 | by wrapping the load attempt in a try block.
| | 00:14 | I'm going to switch the demo. try.
| | 00:22 | A catch block must follow the try
block. The catch block doesn't have to be
| | 00:26 | immediately afterwards, and
other code can execute in between,
| | 00:29 | but it's generally best practice to have
the catch as close to the try as possible.
| | 00:34 | To catch an exception, use the catch
keyword, followed by parentheses containing
| | 00:38 | the class of the exception you wish
to catch, which is the same as what was
| | 00:42 | thrown, and a variable to put
the thrown exception in, if any.
| | 00:46 | Let's catch that exception. catch
parentheses Exception $e. Once caught, you can
| | 00:55 | optionally take further action.
| | 00:57 | In this case, rendering the message that was
included in the thrown exception is sufficient.
| | 01:02 | Often, exception messages
are intended for debugging.
| | 01:04 | So, consider what is actually being
displayed to the user before just displaying
| | 01:08 | an exception message.
| | 01:10 | echo $e getMessage. Save
the demo, then reload the page.
| | 01:17 | The exception message is displayed, which
is much more graceful than a fatal exit.
| | 01:21 | To further customize the exception,
extend the Exception class with your own
| | 01:26 | custom Exception subclass.
| | 01:28 | Go back to your editor, then create a new
file called class.Exceptionaddress.inc.
| | 01:40 | Create a new class named
ExceptionAddress that extends the PHP exception class.
| | 01:46 | class ExceptionAddress
extends Exception. We'll add PHP doc.
| | 01:56 | There are number of built-in methods
that you can override. One of them is the
| | 01:59 | magic to string method. Magic_toString.
return string. public function_toString.
| | 02:12 | Use the magic constant class to
display the name of the current class.
| | 02:16 | Return the class, the exception code, and
the exception message. return_CLASS double
| | 02:25 | quotes {this code} {this message}.
Save the exception address class.
| | 02:40 | Now that the exception is extended as an
exception address, update the load method
| | 02:44 | to throw the new exception address class.
| | 02:48 | Save, then edit the demo script to
catch the new exception address, and use the
| | 02:53 | magic to string method.
| | 02:57 | Save, then run the demo.
| | 03:00 | You will see the new exception
address message, but the code is set to 0,
| | 03:03 | which isn't very helpful.
| | 03:05 | Exception codes are typically integers.
| | 03:07 | Let's use a consonant to
define a custom exception code.
| | 03:11 | Return to your editor, and then go
to the top of your address class.
| | 03:16 | Define a new constant.
| | 03:18 | const ADDRESS_ERROR_NOT_FOUND = 1000.
Then, edit the throw and the load method
| | 03:28 | to include the code.
| | 03:32 | Remember that load is static, so
use the self keyword, not "this."
| | 03:37 | The second argument of
the exception is the code.
| | 03:40 | self::ADDRESS_ERROR_NOT_FOUND.
Save, then reload the demo page.
| | 03:48 | ExceptionAddress now has an error code.
| | 03:51 | If I wanted to define multiple
behaviors, depending on the circumstance, I'd
| | 03:55 | create additional error codes, then
use an if or a switch statement to
| | 03:59 | decide what to do, based on the error code.
| | 04:02 | Throughout this chapter, I've gone
over a number of PHP's built-in objects.
| | 04:06 | I started with generic standard classes,
then retrieved objects directly from the database.
| | 04:11 | We gracefully dealt with potentially fatal
problems, then customized errors to meet our needs.
| | 04:17 | In the next chapter, I'm going to
discuss some common coding design patterns
| | 04:21 | that I've used throughout this course.
| | Collapse this transcript |
|
|
7. Design PatternsIdentifying the singleton pattern| 00:00 | In this chapter, I'm going to explore
a couple of different kinds of design
| | 00:03 | patterns that I've used throughout this course.
| | 00:06 | A design pattern is a reusable
coding solution to common problems.
| | 00:10 | There are dozens of patterns
available to solve all sorts of problems.
| | 00:13 | But in the interest of keeping this
focused on object-oriented programming, I'm
| | 00:17 | just going to discuss three of them.
| | 00:19 | At the end of the course, I'll give you
some resources where you can learn more
| | 00:22 | about design patterns if you'd like.
| | 00:23 | The first pattern I'd like to discuss
is the Singleton pattern, which restricts
| | 00:28 | instantiation of a class to one object.
| | 00:31 | This way, action can be coordinated
throughout the application, and resources can
| | 00:35 | be intentionally limited.
| | 00:37 | I used the Singleton pattern for the
database to ensure that only one connection
| | 00:41 | can occur at a time.
| | 00:42 | Let's look at the database class now.
| | 00:45 | Note the use of the static property
instance to store the singular database
| | 00:48 | connection instance in the database class.
| | 00:51 | Another common use of the Singleton
pattern is lazy initialization, where
| | 00:55 | properties start as null, and
are only populated on-demand.
| | 01:00 | This way, if I try to get a null
property, the LazyInitializer determines the
| | 01:04 | value, sets it, and returns the result.
| | 01:07 | If it's there, just return the value.
The end-result is on-demand access to
| | 01:12 | resources, which is great for reducing overhead.
| | 01:15 | For example, if I don't need to connect to the
database, don't bother making the connection.
| | 01:20 | If I do need the database,
it'll be immediately available.
| | 01:24 | Here is a brief example.
| | 01:25 | I have a class with a protected
property to prevent direct access.
| | 01:29 | I can access the value using the
LazyInitialization function to get the property.
| | 01:34 | If the property is null, initialize it.
| | 01:36 | Regardless of how you got the value,
just return the value of the property at
| | 01:40 | the end of the function.
| | Collapse this transcript |
| Using the factory method pattern| 00:00 | The second design pattern I am going
to demonstrate is the factory method.
| | 00:04 | The factory method is useful for creating
objects without having to specify the class.
| | 00:09 | Sound familiar?
| | 00:10 | Let's look at the Address class.
| | 00:13 | Open the Address class now, and take a
look at the Load in Instance methods.
| | 00:18 | In particular, notice the way that the
returned address_type_id specifies the
| | 00:22 | name of the class to be created in getInstance.
| | 00:25 | However, as it's currently written,
it will fail if it doesn't get the
| | 00:28 | right address type.
| | 00:29 | Let's improve on getInstance to throw
an exception, instead of crashing out.
| | 00:33 | First, create a new constant with an error code.
| | 00:36 | Const ADDRESS_ERROR_UNKNOWN_SUBCLASS = 1001.
| | 00:43 | I am going to go to the getInstance
method, and add a check to see if the class
| | 00:46 | exists, before I instantiate it.
| | 00:48 | I'll use the class_exists
method, which returns a boolean.
| | 00:51 | If not (!class_exists [$class_name]), throw
new ExceptionAddress ('Address_subclass not
| | 01:05 | found, cannot create', self::
ADDRESS_ERROR_UNKNOWN_SUBCLASS);
| | 01:13 | reading through it,
| | 01:14 | if the class does not exist, throw a
new exception address, along with the error
| | 01:19 | code for unknown subclass. Save,
| | 01:21 | then go to the demo source.
| | 01:23 | Instead of explicitly creating an
address residence, use the factory method.
| | 01:28 | Address::getInstance of
(Address:: ADDRESS_TYPE_RESIDENCE);
| | 01:35 | Save the demo, then return
to your browser, and refresh.
| | 01:39 | Everything should look the same.
| | 01:41 | For further practice, switch the
remaining explicit instantiations of address to
| | 01:45 | use the factory method.
| | 01:47 | Then, wrap the getInstance
calls, and try catch blocks.
| | Collapse this transcript |
| Implementing a strategy pattern| 00:00 | The final design pattern I'll
demonstrate is the strategy pattern.
| | 00:03 | A strategy pattern consists of a
group of interchangeable algorithms that
| | 00:07 | perform tasks, then a mechanism
to choose which algorithm to use.
| | 00:11 | That all sounds a bit complex, right?
Let's apply it to an everyday task.
| | 00:16 | When I get up in the morning, I need
to decide what shirt I'm going to wear.
| | 00:19 | I'll look at my stack of clothes.
| | 00:21 | There is a RED SHIRT that's
dirty and a BLUE SHIRT that's clean.
| | 00:24 | For each shirt, I have to decide if it will work.
| | 00:28 | I can't wear the RED SHIRT, because
it's dirty, but I can wear the BLUE
| | 00:31 | SHIRT, because it's clean.
| | 00:33 | If both shirts are clean, I could prefer the
RED SHIRT over the BLUE SHIRT. None are clean?
| | 00:38 | I've run out of strategies, and now
I am going to have to do laundry.
| | 00:42 | In the Exercise Files, I've included
an example of a strategy pattern for
| | 00:46 | displaying an address.
| | 00:47 | There are four files.
| | 00:49 | First, the AddressDisplay class
defines an interface with the methods that
| | 00:54 | implementing classes must use
for displaying an address.
| | 00:57 | In particular, it has a Boolean method
to determine if the strategy can be used,
| | 01:01 | then the display method itself.
| | 01:03 | AddressDisplayNoCountry will cleanly
render an address without a country.
| | 01:08 | I am going to use this
within other display classes.
| | 01:11 | AddressDisplayFull builds upon the
previous address, and displays a full address,
| | 01:16 | including the country.
| | 01:18 | This display method uses
DisplayNoCountry to avoid duplicate code.
| | 01:23 | Finally, AddressDisplayPark, which
displays the address with a green background,
| | 01:28 | with and without a country.
| | 01:29 | I'm going to change the Address class
to use the strategy pattern for display.
| | 01:34 | First, I need to add a constant
for an error, in case there are no
| | 01:37 | strategies available.
| | 01:38 | Const ADDRESS_ERROR_NO_DISPLAY_STRATEGY = 1002.
| | 01:46 | Then, after the property definitions,
add a static property that will contain an
| | 01:51 | array of class names of the display strategies.
| | 01:53 | Order them by the least to most
preferred. private static _display_strategies
| | 02:02 | = array, AddressDisplayNoCountry, followed by
AddressDisplayFull. And then, the most preferred.
| | 02:14 | AddressDisplayPark.
| | 02:17 | After the display strategies, add a
private property that will be used to store
| | 02:21 | the last found display
strategy. private _display_strategy.
| | 02:28 | Next, go to the Display method,
and remove the existing contents.
| | 02:35 | Use the Lazy initialization
Singleton pattern for determining which
| | 02:38 | display strategy to use.
| | 02:41 | If is_null this->_display_strategy
foreach of the self _display_strategies as
| | 02:50 | this strategy_class_name.
| | 02:54 | If the strategy is available, if strategy
_class_name::isAvailable with a context
| | 03:01 | of this, this->_display_
strategy = the strategy_class_name.
| | 03:07 | If no strategies are available, throw
an exception address using the error
| | 03:12 | code defined earlier.
| | 03:14 | throw new ExceptionAddress No display
strategy found, followed by the error
| | 03:22 | code. self::ADDRESS_ERROR_NO_DISPLAY_STRATEGY.
| | 03:27 | Finally, set a variable with the name of
the display strategy, then call the static
| | 03:32 | method for the display. return
display_strategy::display $this.
| | 03:37 | Save the Address class, then
open the AddressPark class.
| | 03:41 | Remove the overriding display method;
| | 03:43 | it's no longer needed. Then, save AddressPark.
| | 03:47 | Return to the browser, and refresh.
| | 03:49 | Each address should display.
| | 03:51 | Experiment with a demo by changing address
types and data to see all the variations.
| | 03:56 | In this chapter, I explored three
different object-oriented design patterns that
| | 04:00 | were used to build this application.
| | 04:02 | I started with a Singleton pattern,
which limited the number of database
| | 04:05 | connections, then moved on to the
factory method pattern for creating addresses
| | 04:09 | without having to know the subclass,
and finally, the strategy pattern for
| | 04:13 | intelligently choosing
how to display an address.
| | 04:16 | Of course, there are dozens of
additional patterns that you can use.
| | 04:20 | In the final chapter, I'm going to
discuss some of the directions you can take
| | 04:23 | in learning more about object-
oriented PHP, which includes design patterns.
| | Collapse this transcript |
|
|
ConclusionLooking forward to namespaces| 00:00 | In this course, I've gone over a
number of ways to organize code,
| | 00:04 | starting with classes, then inheritance,
and abstraction. And, they all included best
| | 00:09 | practices for naming.
| | 00:10 | Is that all there is to know
about organizing code? Of course not.
| | 00:13 | Namespaces are a way of encapsulating
classes, functions, and constants in such
| | 00:18 | a way to solve two primary problems
faced by authors who write reusable code
| | 00:22 | elements: avoiding naming collisions between
your code, internal PHP naming, and third-party code.
| | 00:28 | This happens often with
common verbs like save and load.
| | 00:31 | Namespaces also provide a way to alias,
which shortens overly long names that
| | 00:36 | sometimes get created in an
attempt to avoid naming collisions.
| | 00:39 | This also improves readability.
| | 00:41 | If you've ever encountered these
problems, I definitely recommend checking out
| | 00:44 | namespaces on php.net.
| | Collapse this transcript |
| Next steps| 00:00 | In addition to namespaces, there
are a number of coding frameworks that
| | 00:03 | contain dozens of design patterns
and solutions for many common coding
| | 00:07 | problems and needs.
| | 00:08 | For an in-depth survey of four open
source frameworks, I recommend MVC
| | 00:13 | Frameworks for Building PHP Web
Applications with Drew Falkman.
| | 00:17 | Another course that I will recommend as
a supplement and extension to the design
| | 00:21 | patterns chapter is Foundations of Programming:
| | 00:23 | Object-Oriented Design with
Simon Allardice here in the Lynda.com
| | 00:28 | Online Training Library.
| | 00:29 | Offline, there are two books that are
broadly considered as canonical sources of
| | 00:34 | software design strategies. Design Patterns:
| | 00:37 | Elements of Reusable Object-Oriented
Software, published by Addison-Wesley, and
| | 00:42 | Code Complete, the 2nd
edition, from Microsoft Press.
| | 00:45 | Finally, you may have noticed that one
section the demonstration was not completed,
| | 00:50 | the save method of the Address class.
| | 00:52 | There are many different
ways to approach this problem.
| | 00:55 | You could write a simple SQL query,
and just write the contents to a table
| | 00:58 | within that method.
| | 00:59 | But does that scale?
| | 01:01 | I recommend researching Gateway
patterns along with Object-relational mapping
| | 01:05 | as a starting point.
| | Collapse this transcript |
| Goodbye| 00:00 | We've come a long way together.
| | 00:02 | We started with the base definitions of
what a class and object is to exploring how
| | 00:06 | classes can relate to each other to
practical implementations of design patterns
| | 00:10 | for tackling common programming problems.
| | 00:13 | Hopefully, you'll be able to use some
of the best practices and strategies to
| | 00:16 | organize your application
into manageable, scalable pieces.
| | 00:20 | The best way to learn how to do
something is by actively doing it.
| | 00:24 | Experiment with these tools and techniques,
and find ways to adapt them to your needs.
| | 00:28 | The courses and books I recommended
should help you expand your set of tools,
| | 00:32 | along with using existing PHP frameworks.
| | 00:34 | One of the things that I truly
enjoy about engineering and PHP is the
| | 00:38 | flexibility to design
solutions in a multitude ways.
| | 00:41 | There's usually multiple paths that can be
taken, each with its own strengths and weaknesses.
| | 00:46 | Object-oriented techniques are a great
addition to any programmer's toolset.
| | 00:50 | I appreciate your time, and I hope you
enjoyed watching this course as much
| | 00:54 | as I've enjoyed writing and
recording it while working with a
| | 00:57 | team@lynda.com. Please, take a moment
to provide feedback through the course
| | 01:01 | homepage on Lynda.com.
| | 01:02 | Thank you.
| | Collapse this transcript |
|
|