Page 1 of 1
Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 7:32 am
by mattpointblank
I did a course at university in Java so I have some concept of object oriented programming, so I'm trying to now apply that to PHP.
As a testing point, I'm experimenting with my site's article features.
At the moment, the current page queries the database for the latest 20 articles, then using a variety of messy conditional loops and if statements, it sorts them (in ways I can't do through SQL) - for example, it picks 1 article that has a photo and is in a particular section, and puts that at the top in a large box. It then displays all the articles with photos below that, and then below those, all the articles without photos. It's a mess.
In my test so far, I've made a basic Article class and experimented by making an array of those articles, which is how I envision it working when the results come back from the database.
I've tried running code like this:
Code: Select all
$all_articles = array();
$all_articles[] = new Article('123', 'test headline', 'photo.jpg'); // etc
foreach($all_articles as $article) {
if($article->getFilename() != "") { echo "article has a photo<br />"; }
}
This code works in that it will identify all of the objects with photos, but ideally I'd just like to run a function like this:
Code: Select all
// psuedocode
$articles_with_photos = $articles->getArticlesWithPhotos();
$articles_with_photos->printLargeBox();
I don't know if that makes sense to anyone, but basically I want a way to work with groups of my objects at once, rather than going through foreach/array stuff. Is there a better way to handle all of this?
Thanks
Matt
Re: Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 7:40 am
by Pulni4kiya
You can create a class ArticleCollection and store the Articles in it. And then you can have a method in that class that returns an ArticleCollection object with the articles that have photos. You'll still have to use the foreach in that method though.

Re: Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 9:10 am
by mattpointblank
I did some googling and found a class for collections of objects, since my brain started to hurt when I tried to figure one out alone. This is what I'm using:
http://codeutopia.net/blog/2008/09/17/g ... ns-in-php/
Based on that, my code now looks like this:
Code: Select all
$reviews = new CU_Collection('review'); // new collection of 'review' objects
// todo: fetch rows from the database here and loop through them, creating them as 'review' objects, then adding them to the 'reviews' collection
$article = new review('123', 'this is a headline', 'this is a standfirst', 'this is the review body', '43', 'test category', '12', 'photo.jpg');
$reviews->add($article);
// now get them by category
$reviewsWithImages = $reviews->getReviewsWithImages();
foreach($reviewsWithImages as $rev_with_img) {
echo $rev_with_img->getHeadline();
}
This works fine, and here's the getReviewsWithImages() function inside the CU_Collection class:
Code: Select all
public function getReviewsWithImages()
{
$returnArray = array();
foreach($this->_collection as $key=>$value) {
if ($value->getFilename() != "") {
$returnArray[] = $value;
}
}
return $returnArray;
}
So I still have two foreach loops going on. I don't have anything against them (!), just want to check: is this a good way of doing this? It must be a fairly common need, and I want to learn the most typical, widely-used methods for such things.
Re: Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 9:20 am
by papa
I would look at your dB statement first, why wouldn't it be possible to sort them at that level?
Re: Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 10:13 am
by mattpointblank
The database returns them in a random order (so that the homepage doesn't remain static, and so that a different article appears in the top spot upon page loads). The problem is that for an article to be assigned the top space, it needs to have a photo and be posted under a specific category, which isn't possible to filter for in the SQL along with the random factor - I spent a while trying to find a way but it can't be done.
Say my resultset contains:
review1, no image, category 123
review2, no image, category 666
review3, image, category 999
review4, image, category 123
review5, image, category 123
This means that review4 and review5 are both contenders for the top space (both have an image, both in category 123), so my code has to pick one of them, then display all of the articles with images underneath that, then underneath them, everything else, eg:
review5, image, category 123
review4, image, category 123
review3, image, category 999
review1, no image, category 123
review2, no image, category 666
Anyway - even if it was possible with the query, I still want to use this OOP approach to clean up my code.
Re: Starting out with OOP - arrays of objects?
Posted: Tue Apr 21, 2009 12:33 pm
by Christopher
Code: Select all
class ArticleGroup {
protected $articles = array();
public function add($article) {
$this->articles[$article->getId()] = $article;
}
// or Proxy the creation of articles
public function addArticle($id, $title, $photo) {
$this->articles[$id] = new Article($id, $title, $photo);
}
public function getArticlesWithPhotos() {
$withphotos = arrary();
foreach($this->articles as $id => $article) {
if($article->getFilename() != "") {
$withphotos[$id] = $article;
}
}
return $withphotos;
}
}
Re: Starting out with OOP - arrays of objects?
Posted: Thu Apr 23, 2009 7:15 am
by mattpointblank
Thank you, a little simpler.
I'm trying to sort the array of objects now (again, it's better for me to just grab all the articles using SQL and order them in PHP since I need multiple arrays of them in different orders). I've been looking at usort() but can't really get my head around it.
The array of objects looks like this (simplified):
Code: Select all
Array (
[123] => review Object (
[id:protected] => 123
[headline:protected] => headline goes here
[standfirst:protected] => this is a subheading
[review:protected] => full article text goes here
[imageID:protected] => 11557
)
[456] => review Object (
[id:protected] => 456
[headline:protected] => headline goes here
[standfirst:protected] => this is a subheading
[review:protected] => full article text goes here
[imageID:protected] => 0
)
// etc
}
Say I wanted to sort on the imageID property, so I can put all of the articles with images at the top - how can I do this using usort()? I don't really understand where that function gets its two properties from (or at least, in my case).
Matt
Re: Starting out with OOP - arrays of objects?
Posted: Thu Apr 23, 2009 11:19 pm
by josh
array_multisort or somehting like that. Anyways I just wanted to but in and say I would create 1 method per result area and have the SQL do the sorting. The reason your code seems messy is you're involving arrays and sorting logic. Seriously it will add .00001 to the page load time to pull back a little extra data, but if anything it would be cancelled out by the boost in sorting speed. And you'll save hours of pulling out your hair. It's all about intention revealing interfaces. Its not a big deal how you implement it but your view scripts should be simple, they just accept a collection of results and display them.
So the interface would look like:
interface myInterface
{
public function getResultsWithPhotosInAscOrdering();
public function getResultsWithOutPhotosDescOrdering();
}
If you find yourself creating lots of these hard coded methods it may make sense to look into the repository design pattern. Either that or if you are using an Object Relational Mapper you may have a query object tool and thus would not need to hard the methods ( but hard coding the methods would be superior to duplicating query logic )
It may make sense to seperate out the concerns of sorting. So collections would be returned in an undefined order, then you'd do something like
$collection->sortByReturnValueOf( 'someMethod', COLLECTION::NUMERIC );
Re: Starting out with OOP - arrays of objects?
Posted: Thu Apr 23, 2009 11:34 pm
by Benjamin
It is possible to sort them as required using raw database queries, but if your using database abstraction it would be better to just use an ArticleCollection class to do the sorting. You can use this code to sort mutli dimensional arrays:
Code: Select all
function arrayMultiSortAsc($items,$key){
$compare = create_function('$a,$b','
if ($a["'.$key.'"] == $b["'.$key.'"]) {
return 0;
} else {
return ($a["'.$key.'"] > $b["'.$key.'"]) ? -1 : 1;
}
');
usort($items,$compare);
return $items;
}
function arrayMultiSortDesc($items,$key){
$compare = create_function('$a,$b','
if ($a["'.$key.'"] == $b["'.$key.'"]) {
return 0;
} else {
return ($a["'.$key.'"] > $b["'.$key.'"]) ? 1 : -1;
}
');
usort($items,$compare);
return $items;
}
Usage:
Code: Select all
$n = arrayMultiSortAsc($array, 'imageID');
Re: Starting out with OOP - arrays of objects?
Posted: Fri Apr 24, 2009 3:28 am
by mattpointblank
Thanks guys.
Josh: That approach seems a little complex for me - I'm still getting to grips with objects themselves right now, let alone interfaces... I hear you about the query stuff, but I prefer the idea of running a single query then breaking it into separate arrays of filtered content, so I can reuse these on other parts of the site and format them more specifically as well.
astions: I tried that code and got:
Fatal error: Cannot use object of type review as array in /dev/functions.php(126) : runtime-created function on line 2
I'm running the function on the results returned by this method:
Code: Select all
public function getAllReviews()
{
$allReviews = array();
foreach($this->articles as $id=>$article) {
$allReviews[$id] = $article;
}
return $allReviews;
}
Re: Starting out with OOP - arrays of objects?
Posted: Fri Apr 24, 2009 4:09 am
by josh
mattpointblank wrote:Josh: That approach seems a little complex for me - I'm still getting to grips with objects themselves right now, let alone interfaces... I hear you about the query stuff, but I prefer the idea of running a single query then breaking it into separate arrays of filtered content, so I can reuse these on other parts of the site and format them more specifically as well.
The point of OOP is that your code should only care about the interface, not the implementation. If there is a method to get each collection, what does it matter if behind the scenes the data is loaded in separate steps or all at once, all your code should care about is that it calls each method and it gets the data back that it needs. Perhaps your constructor could load the data and various methods could return subsets of that data.
Re: Starting out with OOP - arrays of objects?
Posted: Fri Apr 24, 2009 12:27 pm
by Benjamin
mattpointblank wrote:
Fatal error: Cannot use object of type review as array in /dev/functions.php(126) : runtime-created function on line 2
Yeah, it actually needs to be a multidimensional array, not an array of objects.