Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Cool Object Building With PHP
1. Cool Object Building With PHP
February 24, 2009 at 1:16 am
At work I write mostly PHP code and work among some very respected
developers in the PHP community. One thing that bothers me about the PHP
world is how most people think in terms of arrays instead of in terms of objects.
This is understandable considering Object OrientedPHP didn't really come around
until PHP 5 so using arrays is probably an old habit that is hard to get rid of, but
that is no excuse. Arrays have their uses, but I think more often than not an
object can be used instead.
One of the core problems most PHP developers run into is finding a way to map
records in the database to PHP objects. This is understandable considering your
database model is often very different from your object model, and at the
moment PHP does not offer any great solutions that I know of. Basically my
proposal involves two parts:
1. a DAO (data access object) class
2. a Builder class
What these classes do is very simple: The DAO contains the SQL to query the
database and then calls a builder to take the resulting array and assemble an
object (or a collection of objects) out of it which is then returned.
This implementation allows for no question about what is being returned and it
forces you to use more objects in your code which is never a bad thing. Another
plus is that you can cache the collections directly in memcache and therefore
when you hit cache your PHP doesn't have to do any work at all with the data.
This is actually the method I am using on this site so I will demonstrate using real
world examples, but before I do so I want to point out that much of the
awesomeness in the example relies on a certain naming pattern for your classes.
For example I have classes named Blog_Dao, Blog_Comment, Blog_Builder, etc.
The first code I am going to show you is the base DAO class I am using:
1 <?php 2 class Dao 3 { 4 /** 5 * @var Db 6 */ 7 protected $_db; 8 9 /** 10 * @var Builder 11
*/ 12 protected $_builder; 13 14 /** 15 * constructor 16 * 17 * sets the database class this dao
should use 18 * 19 * @return void 20 */ 21 function __construct() 22 { 23 $this->_db = new
Db(); 24 } 25 26 /** 27 * determines what builder class to use 28 * 29 * @param string $builder
30 * @return Builder 31 */ 32 protected function _getBuilder($builderName) 33 { 34 // if we have
already instantiated a builder class 35 if (!is_null($this->_builder)) { 36 return $this->_builder;
37 } 38 39 // if we have not passed in a specific builder to use 40 if (is_null($builderName)) { 41
$builderName = str_replace('_Dao', '_Builder', get_class($this)); 42 } 43 44 // make sure the
builder exists 45 if (!class_exists($builderName)) { 46 throw new Exception($builderName . ' does
not exist!'); 47 } 48 49 // instantiate the builder 50 $this->_builder = new $builderName; 51 52
return $this->_builder; 53 } 54 55 /** 56 * calls the builder to build a collection of the stuff
2. returned from the 57 * dao! 58 * 59 * @param mixed $records 60 * @param string $builder
name of class to use for building 61 * @return Collection 62 */ 63 protected function
_buildCollection($records, $builder = null) 64 { 65 // if the database doesn't have any records 66
if ($records === false) { 67 return false; 68 } 69 70 $collection = new Collection(); 71 foreach
($records as $record) { 72 $collection->append($this->_buildOne($record, $builder)); 73 } 74
return $collection; 75 } 76 77 /** 78 * calls the builder and builds a single object 79 * 80 *
@param mixed 81 * @param string $builder 82 * @return Object 83 */ 84 protected function
_buildOne($record, $builder = null) 85 { 86 // if the database doesn't have any record 87 if
($record === false) { 88 return false; 89 } 90 91 $builder = $this->_getBuilder($builder); 92
return $builder->assemble($record); 93 } 94 } 95
The first thing you will probably notice is that $builder is optional! This means you
only need to pass in a builder class if the builder is in some wacky place it
shouldn't be. So the Blog_Comment_Dao class will default to the
Blog_Comment_Builder which makes sense and it forces good use of objects
cause it means everything you create a dao for is an object and that DAO should
only return things related to that object. Another point of note is the Collection
object. This is simply a child of ArrayObject to allow easier access to ArrayObject
methods.
Anyway now it is time to see this in action! Here is actual code from this site to
get all comments related to a given blog post taken from the Blog_Comment_Dao
which extends the base Dao class:
39 /** 40 * retrieves all comments for a given blog 41 * 42 * @param int $blogId 43 * @return
Collection 44 */ 45 public function get($blogId) 46 { 47 $query = '/* ' . __METHOD__ . ' */' . 48
"SELECT bc.id id, 49 bc.name name, 50 bc.website website, 51 bc.email email, 52 bc.body body,
53 bc.posted_on posted_on 54 FROM blog_comment bc 55 WHERE bc.blog_id = :blog_id"; 56 57
$sth = $this->_db->prepare($query); 58 $sth->bindValue(':blog_id', $blogId); 59 $sth-
>execute(); 60 $records = $sth->fetchAllAssoc(); 61 62 return $this->_buildCollection($records);
63 }
Look how pretty that is! Now let's take a look at the Blog_Comment_Builder class
to see how simple that is as well:
1 <?php 2 class Blog_Comment_Builder 3 { 4 /** 5 * creates a comment object from database
record 6 * 7 * @param array 8 * @return Blog_Comment 9 */ 10 public function assemble(array
$record) 11 { 12 $comment = new Blog_Comment(); 13 $comment->name = $record['name'];
14 $comment->website = $record['website']; 15 $comment->email = $record['email']; 16
$comment->body = $record['body']; 17 $comment->postedOn = new
Date($record['posted_on']); 18 return $comment; 19 } 20 } 21
Something to note here is that these are not public properties. They are all
protected, but each domain object extends a Domain_Object class that has magic
__set() and __get() methods so you don't have to write setters and getters for
every single property in every single class! For more on that check out this
post by Matthew Purdon.
You can see that properties of objects can still be other objects such as the Date
class here. In the case where you are showing a bunch of Users on your site and
3. each one has a bunch of other classes associated it with it you probably wouldn't
want to use the other class's builders because then you end up running queries in
loops which is never a good thing. Instead you can handle that logic in the
User_Builder cause at the end of the day even if there are other classes involved
the Builder is just returning one object from one database record.
An obvious downfall here, of course, is that every object needs to have its own
Builder class even though the builder seems like something that could happen
automatically if there was better ORM support in PHP or any for that matter. This
is something that PHP developers are used to, however, because no matter what
framework you use, you still end up having to write tons of code to do even
simple operations. Hopefully this will make your life easier.