Day two of the two day object-oriented PHP seminar. Builds on the concepts from day one and touches on more advanced topics such as polymorphism, design patterns, unit testing, and writing SOLID code
2. Quick Refresher/Warm-up Design a User class What properties should it have? What methods? Including getters/setters What are some likely child classes?
3. Abstract Classes/Methods Flags a class/method as “incomplete” Classes w/abstract method(s) must be abstract Instantiating an abstract class throws a PHP error Examples
4.
5. Overriding methods Child classes can redefine parent methods Depends on visibility Can call original version with parent::methodName()
6. Overloading methods Defining multiple methods with the same name, but accepting different arguments Not natively supported in PHP To fake it, use func_get_args()
8. Final keyword Prevents a method from being changed in child classes Can also apply to a class as a whole This is the only way to make properties final Not very common Example
9. Magic methods Start with __, like __construct() Called automatically when certain things happen Examples: __toString() __get() and __set() __clone() __sleep() and __wakeup()
10. Exceptions Errors as objects Native PHP errors or user-defined throw new Exception(); Allows use of try/catch blocks SPL adds new Exception types ErrorException object
11. Static keyword Adds functionality directly to a class itself Doesn’t require instantiation to use No access to $this Can make things harder to test Example ArrayUtils Session::start()
12. Class autoloading Define function(s) to tell PHP where to find undefined classes Can define multiple functions with spl_autoload_register() Zend or PEAR naming conventions Bear_Polar lives at Bearolar.php on the file system
13. Testing object equality $a = $b Create a reference $a == $b Type compare only $a === $b Do $a and $b point to the exact same object instanceof Tests “is, extends, or implements” if ($dtinstanceofDateTime) {…}
14. Object cloning How to actually copy an object $a = $b just makes a reference $a = clone($b) makes an actual new object __clone() magic method
15. Object serialization Convert an object to a string for storage Commonly used when storing objects in a session file or a db “object” or “document” databases like MongoDB use this heavily serialize() / unserialize() __sleep() and __wakeup()
16. Example PHP core objects Easy SimpleXML DateTime More powerful/complex DomDocument PDO Honorable mention mysqli
17. Best Practices - Documentation Learn and use the PHP Docblock syntax Annotations are becoming more popular/powerful IDEs use this info to help you Can also generate skeleton docs for you PHPDocumentor
18. Dependency Inversion/Injection Don’t look for things, ask for them If your class need a db connection, make it a required constructor argument Makes code easier to modify/test Dependencies are explicit
19. Design Patterns Widely-accepted solutions to common problems Often language-neutral (i.e. steal from Java) Anti-patterns/“code smells” “You fell for one of the classic blunders”
20. Example Design Patterns Examples Factory (and Factory Method) Value Object ActiveRecord Example anti-pattern God Class
21. Polymorphism Behavior determined by class/subclass Using same method name, just different implementations Simplifies logic, better encapsulation Example From Wikipedia: polymorphism.php DataWriter
22. Unit Testing Writing tests (in PHP) to verify your code Test the smallest possible chunks (units) of code Test for results, not implementation Every requirement/bug should have tests PHPUnit Most IDEs can build test skeletons for you
24. Final exam! Design a blog using OO principles Requirements: Users must be authenticated to submit content Comments are allowed Produce a list of the most recent 10 entries
25. Final exam! Write a simple Database Abstraction Layer (DBAL) Requirements: Supports Oracle and MySQL Supports bound query parameters Can fetch, add, update, and remove records Implements the ExampleDBAL interface
26. Resources The gold standard for OO code: http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29 PHPUnit http://www.phpunit.de (it’s in English) PHPDocumentor http://www.phpdoc.org/ Code Complete 2 An actual book, and a massive one at that http://www.phpfreaks.com/tutorial/oo-php-part-2-boring-oo-principles This covers a lot of the SOLID stuff in more detail
Editor's Notes
User or BaseUser. Should probably have firstName, mi, lastName, phone1, phone2, areaCode, email, potentially an “authenticated” flaggetPhone, getName, plus individual chunks. Possibly authentication method but that’s a good choice to factor out to its own classLikely child classes – AdminUser, GuestUser, PowerUser, etc…Was this helpful? Should we design a small app like a blog?
Most often used for “base” classesAnother way to create an “abstract” class is to have your constructor throw an ExceptionIf all of the methods in your class are abstract, then you’re better off making an Interface instead so you don’t use up your one shot at inheritance. Show BaseBear
An interface is like setting a contract with users of the class. It’s a list of things that you all agree has to be there. It makes no mention of how these methods are implemented, as long as they exist. They can even be empty.This makes testing your code much easier. I’ll cover unit testing near the end of today.Still some variation on naming… some say iBearFood, some say BearFood_Interface, some say just call it BearFood (implements keyword gives it away) A quick jump back to Day 1 where we tried to type hint PoohBear…
We’ve actually already used this but it certainly merits its own slide. This is a very important part of OO design.Remember that you can only override public and protected methods that aren’t final. Ideally they should keep the same method signature (params, types & defaults) too or you’ll generate E_STRICT errorsIn general it’s a good idea to call the parent constructor, if one exists, just to make sure everything got built properly. Show PolarBearFinal example of constructor
I bring this up mostly for the benefit of those who have already studied other languages, especially strongly-typed languages like C++ or JavaPHP’s way to handle this would be to pass an array of arguments instead. To provide defaults, make (for example) a $_defaultOptions property and array_merge() that and the user’s passed array of $options
Fairly self-explanatory. The most common use case I see for this is a protected method that the class author wants to lock down, so they will use protected final in their method signature.Private final makes no sense.
The most important thing to say here is to use these sparingly, if at all. With the exception of __construct() these are more like shortcuts or crutches. Relying on magic makes your code harder to understand. They’re also significantly slower than using native code. The PHP manual has a list of all of the available magic methods. Don’t start method names with __ in case of future conflicts. The only ones I’d really use would be __construct, __toString, and very rarely, __destructA side note on overloading… some people refer to the use of __get and __set as “overloading” a class. Again, this term is used differently elsewhere
Exceptions are like errors on steroids. You have much more control using exceptions than you do with native PHP errorsObjects, so you can type hint. Try/catch is really powerful error handling. Remember to release expensive resources in catch block if your program is giving up to mitigate DoS attacksExceptions are by far the most common use of “empty” classes. If you want to extend a native PHP Exception and just change the name, that’s both allowed and encouragedExceptions have useful methods like getMessage, getFile, getLine, etc…
Sometimes you have functionality that you want to contain in a class, but you need or want to use it without having to instantiate an object first. Since you aren’t working with an instantiated object, you can’t use the $this keyword in static methods, even If you’re calling a static method from an object instanceThe best use of static methods I can think of is either a “Utilities” class to group related custom functions, like StringUtilities or ArrayUtilities, OR a class that doesn’t persist any data, like the Session class from the web forum
I promised to show you how to avoid typing require_once 30 times/app, and here it is. In PHP4 you could define a function called __autoload() that would run if a class wasn’t found. Now in PHP5 you can define as many autoloaders as you want using the SPLNaming conventions become very important here. If you follow them strictly your autoload functions become much easier to write. We recommend following the Zend or PEAR standard here. They’re nearly identical. Case matters.A further advantage of autoloading is it lets you “lazy load” only the code you actually need for a request. This can result in less code being run than requiring the entire pile of functions every time.
I originally called this slide “comparing objects” but then I’d also have to get into how to test if an object is greater than another object, less than, etc… and that was just too much. The slide basically speaks for itself, but the main takeaway here should be to always use strict comparison (===) or instanceofinstanceof can also test interfaces and parent classes. PolarBearinstanceof Bear would evaluate to true since PolarBear extends Bear. Type hinting is based on instanceof
Object cloning is rarely used in my experience. This tends to be more of a gotcha than a feature. The only time I’ve used clone that I can remember was on a calendar. I made a start DateTime object, cloned it, and added a week to the clone so I could have an end DateTime object.
I used to advocate storing lots of objects as strings from page to page for the sake of speed, but building objects is cheap, and if you’re not careful you can lose some property values during serialize/unserialize, esp. references to a db connectionThat being said, I do recommend making a few objects, serializing them, and echoing them out to the screen just so you can get a bit of practice decoding the format. I’ve found that knowledge to be very helpful several times. For example, PEAR stores its configuration information as a serialized object, so knowing how to read the format means you can edit that file directly. It’s basically type/length/value
This is just a sample of some of the built-in PHP objects. SimpleXML really is a dead-simple way of interacting with XML in an object-oriented format. Every node is a document tree becomes a SimpleXML instance. DateTime we already covered.I never use DomDocument or PDO directly, so if you want more information on them, check the docs. That being said, nearly every DBAL written for PHP is based off of PDO, so you should at least learn how to build a PDO connection stringI just bring up mysqli here because it was one of the first PHP objects I used heavily. Converting an app from mysql functions to mysqli methods was good early syntax practice
Everybody hates documentation, but in this case a smart IDE can make documentation easier to write and useful to YOU while you’re coding. Again, we recommend following the documentation standard that goes with the Zend or PEAR coding standardsThings like @param or @return are called annotations, and they are used by IDEs to help you with code completion and to fill in informational pop-ups. Also, several coding projects (including PHPUnit, which we’ll get to later) add even more power to annotations, to the point where they can affect the functionality of codeLast trick: PHPDocumentor is a FOSS project to scrape your code for docblocks and generate a really robust set of API documentation for your code in a variety of formats, even PDF
Remember from Day 1 when we turned most of the Bear’s properties into constructor arguments? This is why. If you need to test your class, you can pass in fake versions of what it needs without modifying the class itself, ex. A db connection that doesn’t issue any queriesMakes it easier to see how classes relate to each other and in what order they need to be builtRule of thumb: you should not have the “new” keyword inside a class unless that class’s sole purpose is to build objects (called a Factory) OR you’re building a simple Value Object (sometimes OK)
I love design patterns. They’re like having a math textbook that has the answers to all the odd-numbered problems in the back. In the past 40 years or so programmers have run into many of the same problems over and over again, and design patterns are like those solutions that have risen to the top of the pile, like a coder’s version of a solutions knowledgebase. Most of them are designed around OO principles rather than being language-specific, and many are segmented enough that you can find objects already written whose sole purpose is to implement a specific pattern in your code.
A Factory is an object whose purpose is to build other objects. Advantages: centralized logic for “constructors”. Allows running additional setup methods. Can allow object caching. A Factory Method is the same thing only as a single method instead of a whole class (ex. PEAR Mail)A Value Object is a very small, lightweight object designed to add just a little bit more functionality to a “primitive type” like an integer or string. Classic example is a Money object: can do currency conversion and know what type of digit separator to use. DateTime is another example of a Value Object, as is GenderActiveRecord is a somewhat Microsoft-centric way of dealing with databases. An “ActiveRecord” object will have methods to query the database for a collection of rows, and then it will populate the object’s properties with the values of the “current” recordA God Class is a class that is all knowing and all seeing… in other words it’s way too large and breaks the “single responsibility” principle. A good warning for this is if the best name you can come up with for your object is the name of the app itself. If you can’t figure out what to name a class there’s a good chance you need to rethink its design. The same holds true with methods too, and even variables if you’re picky enough.
From being involved in several programmer interviews, I can say that most people get this wrong. It’s somewhat tricky to explain because it involves several different concepts that mean different things in different contexts, so if this doesn’t make sense until after the example that’s perfectly fine. Polymorphism, to me, means having multiple objects with the same method signature, and the code that uses them doesn’t know or care which is which. The type of the object (rather than the method used) determines the outcome. It is ideally suited to the Factory pattern
The best example I can give for this is one of a car. If you were going to “unit test” a car, you would individually test as many pieces as you could, like testing the knob on the radio, the turn signal, the spark plug, etc… then the only real test you’d have left is turning it on and driving it to make sure all the pieces were hooked together properly. Testing everything as a whole is called a functional test.Having a full test suite lets you make changes in your code and knowing immediately if your changes break anything. It’s a really liberating feeling, and writing tests for your code will make you think about both the design of the code and a lot of the edge cases that you might not have coded for originally.The true pinnacle of this philosophy is called Test-Driven Development, in which you write the tests for your code before you write your code. Writing tests for TDD becomes part of your app design process because the tests determine your API.
I’m kidding of course, but if you DO have questions about anything we’ve covered in either day, now would be a good time to ask them.
Feel free to work in pairs or small groups on this. You can easily use 6 or more objects for this so don’t be stingy. For extra credit you can start coding the objects, or at least produce interfaces for them.
Feel free to work in pairs on this. I do expect it to take awhile and we’ll be around to help if you have questions. I recommend starting with MySQL first.
Parting thoughts: problems are MUCH cheaper to fix earlier on in the process. It’s almost always worth it to put some serious thought into the design/requirements part of an app BEFORE you code. Sketch it out on a piece of paper or use a mind-mapping software or flowchart. It will take a while for the OO frame of mind to sink in and become automatic, whether it’s a few months or a year or more. Don’t give up on it. Once you get it, you’ll never want to go back.