navigate site menu

Start learning with our library of video tutorials taught by experts. Get started

Object-Oriented Programming with PHP
John Hersey

Object-Oriented Programming with PHP

with Jon Peck

 


Whether you're enhancing or optimizing existing code or just starting from scratch, there's never a better time to start integrating object-oriented design techniques. This course shows how to integrate the principles of object-oriented programming into the build of a PHP-driven web page or application. After an overview of what objects and classes are and why they should be used, author Jon Peck dives into creating and instantiating objects, then defining the class relationships and interactions that will form the basis of your coding arsenal. The course also shows how to leverage PHP objects and implement design patterns, and looks at steps you can take to continue adding to your programming tool belt.
Topics include:
  • Historical overview of object-oriented PHP
  • Defining classes
  • Creating a method/object context with $this
  • Accessing classes without instantiation
  • Creating a database class
  • Extending and abstracting classes
  • Cloning and comparing objects
  • Error handling with exceptions
  • Implementing design patterns, such as the factory and strategy patterns

show more

author
Jon Peck
subject
Developer, Programming Languages
software
PHP
level
Intermediate
duration
1h 57m
released
Sep 26, 2012
updated
Apr 10, 2013

Share this course

Ready to join? get started


Keep up with news, tips, and latest courses.

submit Course details submit clicked more info

Please wait...

Search the closed captioning text for this course by entering the keyword you’d like to search, or browse the closed captioning text by selecting the chapter name below and choosing the video title you’d like to review.



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


Suggested courses to watch next:


PHP with MySQL Beyond the Basics (10h 27m)
Kevin Skoglund


Are you sure you want to delete this bookmark?

cancel

Bookmark this Tutorial

Name

Description

{0} characters left

Tags

Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading
cancel

bookmark this course

{0} characters left Separate tags with a space. Use quotes around multi-word tags. Suggested Tags:
loading

Error:

go to playlists »

Create new playlist

name:
description:
save cancel

You must be a lynda.com member to watch this video.

Every course in the lynda.com library contains free videos that let you assess the quality of our tutorials before you subscribe—just click on the blue links to watch them. Become a member to access all 104,069 instructional videos.

get started learn more

If you are already an active lynda.com member, please log in to access the lynda.com library.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Get access to all lynda.com videos

You are currently signed into your admin account, which doesn't let you view lynda.com videos. For full access to the lynda.com library, log in through iplogin.lynda.com, or sign in through your organization's portal. You may also request a user account by calling 1 1 (888) 335-9632 or emailing us at cs@lynda.com.

Access to lynda.com videos

Your organization has a limited access membership to the lynda.com library that allows access to only a specific, limited selection of courses.

You don't have access to this video.

You're logged in as an account administrator, but your membership is not active.

Contact a Training Solutions Advisor at 1 (888) 335-9632.

How to access this video.

If this course is one of your five classes, then your class currently isn't in session.

If you want to watch this video and it is not part of your class, upgrade your membership for unlimited access to the full library of 2,024 courses anytime, anywhere.

learn more upgrade

You can always watch the free content included in every course.

Questions? Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com.

You don't have access to this video.

You're logged in as an account administrator, but your membership is no longer active. You can still access reports and account information.

To reactivate your account, contact a Training Solutions Advisor at 1 1 (888) 335-9632.

Need help accessing this video?

You can't access this video from your master administrator account.

Call Customer Service at 1 1 (888) 335-9632 or email cs@lynda.com for help accessing this video.

preview image of new course page

Try our new course pages

Explore our redesigned course pages, and tell us about your experience.

If you want to switch back to the old view, change your site preferences from the my account menu.

Try the new pages No, thanks

site feedback

Thanks for signing up.

We’ll send you a confirmation email shortly.


By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

Keep up with news, tips, and latest courses with emails from lynda.com.

By signing up, you’ll receive about four emails per month, including

We’ll only use your email address to send you these mailings.

Here’s our privacy policy with more details about how we handle your information.

   
submit Lightbox submit clicked