My question is more like a theoretical.
Say you have an object, that represents the list of something (articles, pages, accounts etc.)
class ObjCollection
You have a class, that represents a specific item in collection:
class objItem
I have a problem thinking of a basic responsibilities of each object.
Which class is responsible for creating a new objItem?
Which class is responsible for deleting a objItem? Should it delete itself as a method?
Update 1:
Techpriester: Is it ok to use object's constructor as a function to create new item?
I think of that like:
class objItem {
public function __construct($id = 0) {
if ($id > 0) {
// load item data...
} else {
// make new item...
}
}
}
But what if something goes wrong in the code, and instead of passing an $id > 0, it passes 0? In this case a more expected behavior would be an empty object, and not the new one, or am I wrong?
A way of thinking about this:
objItem usually have a class constructor so this class might be responsible for creating objects of type objItem.
When an objItem is inserted in a list/collection let's say objCollection it can be objCollection responsability to delete it from the collection.
objItem usually have a class
constructor so this class is
responsible for creating objects of
type objItem.
Constructor has nothing to do with responsibility (usually). Thinking this way, every object would be only responsible for itself.
Responsiblity is a concept not directly binded with class hierarchy.
If:
ObjCollection = Nest objItem = Egg. And there is third object Bird, Then Bird takes responsibility for creating egs (even if nest contains egg). It is not about programming it is about common sense... :)
There is not such thing like "empty object". Objects have "state". You can create an object and then you have it, or you may not to create it and there is no object then.
All you have to worry about is if your constructor will work fine in both cases, with new object created and without it.
Usually it is better to inject object as a constructor parameter (instead of $id) not to create it inside another object.
I know this doesn't answer your question, but since you tagged this as PHP I'm going to assume that it will almost certainly be applied with some sort of database model.
In that case, it's probably a better idea to do away with 'collections' altogether since if you made each class represent only one object, if you wanted to view 10 blog posts, for example, you would be calling 10 separate SELECT queries each retrieving only an individual database record, because you decided to have the 'BlogPost' class encapsulate its retrieval method.
The alternative is to let the class represent either one or more records, that way, you only need to run one SELECT query whether you're retrieving 5000 records or only one. Pretty much every object-relational-mapper does this.
When doing object-oriented programming, it's better to think in terms of behavior or responsibility than whether or not the object is a tangible 'thing'. That's the problem with theoretical discussion of OOP. It's very tempting to use analogies like animals and fruits which have very little relevance to real-world programming.
Since an object cannot delete itself, that has to be the responsibility of the collection.
Wether you let the collection create it's objects like $collection->makeNewItem(); (which then calls the items constructor) or use $item = new Item(); directly and then some $collection->addItem($item);method is entirely up to you and the needs of your application.
I'd recommend using regular instantiation if the items themselves are also used outside of the collection.
Related
I'm just wondering if someone can help me understand how to make the best use of objects in PHP.
My understanding of a PHP object is that is should represent an entity, providing methods to get and alter the properties of that entity. For example an object entitled Post would hold all the properties of a single post, which could be accessed and modified as appropriate.
What causes me some confusion is that libraries like CodeIgniter don't use objects in this manor. They treat classes more like wrappers for a group of functions. So a 'Posts' class in CodeIgniter would not hold properties of one post, it would provide functions for fetching, editing and deleting posts.
So what happens if I want to get every post out of a database and put it into a Post object? My understanding of it is I would in fact need two classes 'Posts' and 'Post', one that defines the Post object and one that handles fetching the Posts from the database and putting them into Post objects.
Do these two types of class have a name ('Proper' objects / Collections of functions)? And is it common to have two classes working together like this or have I completely misunderstood how to use objects?
Instead of having a Post object would it make more sense to have a method in my Posts class called getSinglePost($id) that just returned an array?
Hopefully that question makes sense, looking forwards to getting some feedback.
For an introduction, see What is a class in PHP?
For the answer, I'll just address your questions in particular. Search for the terms in bold to learn more about their meaning.
My understanding of a PHP object is that is should represent an entity, providing methods to get and alter the properties of that entity.
Entities are just one possible use for objects. But there is also Value Objects, Service Objects, Data Access Objects, etc. - when you go the OO route, everything will be an object with a certain responsibility.
What causes me some confusion is that libraries like CodeIgniter don't use objects in this manor.
Yes, Code Igniter is not really embracing OOP. They are using much more of a class-based-programming approach, which is more like programming procedural with classes and few sprinkles of OOP.
They treat classes more like wrappers for a group of functions. So a 'Posts' class in CodeIgniter would not hold properties of one post, it would provide functions for fetching, editing and deleting posts.
That is fine though. A posts class could be Repository, e.g. an in-memory collection of Post Entities that has the added responsibility to retrieve and persist those in the background. I'd be cautious with Design Patterns and Code Igniter though since they are known to use their own interpretation of patterns (for instance their Active Record is more like a Query Object).
So what happens if I want to get every post out of a database and put it into a Post object?
Lots of options here. A common approach would be to use a Data Mapper, but you could also use PDO and fetch the data rows directly into Post objects, etc.
My understanding of it is I would in fact need two classes 'Posts' and 'Post', one that defines the Post object and one that handles fetching the Posts from the database and putting them into Post objects.
That would be the aforementioned Repository or Data Mapper approach. You usually combine these with a Table Data Gateway. However, an alternative could also be to not have a Posts class and use an Active Record pattern, which represents a row in the database as an object with business and persistence logic attached to it.
Do these two types of class have a name ('Proper' objects / Collections of functions)? And is it common to have two classes working together like this or have I completely misunderstood how to use objects?
Yes, they work together. OOP is all about objects collaborating.
Instead of having a Post object would it make more sense to have a method in my Posts class called getSinglePost($id) that just returned an array?
That would be a Table Data Gateway returning Record Sets. It's fine when you don't have lots of business logic and can spare the Domain Model, like in CRUD applications
Class should ideally has the same interpretation as anywhere else in PHP as well. Class starts with abstraction, refining away what you don't need. So it's entirely up to you to define the class the way you want it.
Codeigniter does have a strange way of initiating and accessing objects. Mainly because they are loaded once and used afterwards, prevents it from having functionality around data. There are ways around it and normal handling of classes still possible. I usually use a auto loader and use normal classes.
"So what happens if I want to get every post out of a database and put it into a Post object? My understanding of it is I would in fact need two classes 'Posts' and 'Post',"
You are essentially referring to a MODEL to access the data ("posts") and an Entity to represent the "post". So you would load the model once and use it to load up as many entities as you would like.
$this->load->model("posts");
$this->posts->get_all(); // <- This can then initiate set of objects of type "Post" and return. Or even standard classes straight out from DB.
Your understanding of an object is correct. A post is a single object of a class Post. But of course you need a function, that retrieves posts from a database or collects them from somewhere else. Therefore you have so called Factory classes. That's what can cause some confusion.
Factories can be singletons, which normally means that you have one instance of this class. But you don't need to instantiate a factory at all (and instead use static functions to access the functionality):
$posts = PostFactory::getPosts();
And then the function:
static function getPosts() {
$list = array();
$sql = "select ID from posts order by datetime desc"; // example, ID is the primary key
// run your sql query and iterate over the retrieved IDs as $id
{
...
$post = new Post($id);
array_push($list, $post);
}
return $list;
}
Inside this factory you have a collection of "access"-functions, which do not fit elsewhere, like object creation (databasewise) and object retrieval. For the second part (retrieval) it is only necessary to put the function into a factory, if there is no "parent" object (in terms of a relation). So you could have an entity of class Blog, you instantiate the blog and then retrieve the posts of the blog via the blog instance and don't need a separate factory.
The naming is only there to help you understand. I wouldn't recommend to call a class Post and it's factory Posts since they can easily be mixed up and the code is harder to read (you need to pay attention to details). I usually have the word "factory" mixed in the class name, so I know that it is actually a factory class and others see it too.
Furthermore you can also have Helper classes, which don't really relate to any specific entity class. So you could have a PostHelper singleton, which could hold functionality, which doesn't fit neither in the object class nor in the factory. Although I can't think of any useful function for a Post object. An example would be some software, which calculates stuff and you have a Helper, which performs the actual calculation using different types of objects.
Lets say I have two classes in PHP, a book class and an author class. Lets say I were to create a new book object.
// $book is now a book class
$book = new book('War and Peace');
Now lets say I want the author from that book. To do so, my object setup requires me to get the author class from the book.
// gets an author class chained with a method to get it's name
$author = $book->getAuthor()->getName();
In the $book->getAuthor() call, would it be best to "save" the author object to a property in book?
public function getAuthor()
{
if(is_null($this->author_object)) {
$this->author_object = new author($this->author_name);
}
return $this->author_object;
}
The example is probably not the best, but I hope it represents my question well. Also, I know already that database look-ups are a big performance hit, so pretend that is not needed for now.
Basically my question is what is better, creating the author object again if its needed, or saving the author object as a property so it doesn't need to be created again.
Yes, it's better to save the Author object as a property of the Book object if you are likely to re-use the author data. However, then you have to worry about things like what happens if you instantiate another Book object that has the same author, and persist changes to that author to the DB using the new Book's object. Then your original Book will have an out-of-date Author object with inconsistent data.
Propel ORM uses a global Instance Pool of related objects to make this process easier. (Although, I'm not sure if it actually maintains consistency in the situation described above, because I seem to recall encountering bugs having to do with that, but it at least prevents database queries to get objects that have already been seen.) In any case, Propel is a nice ORM with exactly the same syntax for related objects and fields as you use, so you might want to consider using it.
Generally speaking its pretty hard to imagine a case where it would not be the expectation that that Author is a stored within the Book class and that the Book would not be a member of the Books property on the Author. IT would be fine for them to "lazy load" which is what your example does, but after loaded you would expect to reference the same object with repeated calls, not just the same data.
But there could be instances where that doesnt happen, but then id argue with your choice of naming the method like a basic accessor :-)
I have an abstract class called Node. It contains a constructor that takes a row from my database, and instantiates basic information. All pieces of content on my website extend this class - Person, Event, Project, etc.
3 of these extending classes are special - when they are constructed, in addition to pulling values from the database, they also need to query a web-service; if the web-service provides values that are different from the ones given in the DB, they need to save to the DB.
In a multiple-inheritance capable language, this would be fairly simple; any one of these classes would extend both Node, and APIData, or something like that. Without MI, I'm not sure how to handle this. Using an interface would not be helpful, as that provides no concrete implementations.
The decorator pattern is sometimes recommended as a substitue for some features of MI, but I don't have enough experience to determine if this is the appropriate choice. Any suggestions?
Objects should be dumb. When I construct something, it shouldn't be doing anything other than what I ask it - i.e. construct yourself. Don't be querying webservices and writing to the database. If I was using your objects as another developer on your team, I would be shocked.
This is also why I think you are struggling for the correct pattern, because your object has multiple concerns.
I think the best approach here would be to create a service that returns objects, such as a PersonService, EventService, etc., that does the following:
Retrieve record from the database
If need to check webservice:
Retrieve data from webservice
If changes exist, save back to database
Pass record to object contructor
Return object
This keeps the concerns of the webservice call in a place where it makes sense - that is, the code that retrieves the necessary data to construct and return objects, aka a service (EDIT: actually more of a DAO, but you get the idea).
Since the APIData class will take functionallity from your Node class, you should simply extend it. Here is some pseudo code:
abstract class APIData extends Node {
public function __construct($data) {
parent::__construct($data);
$this->checkData();
}
protected function checkData() {
// load data from webservice
$data = $this->loadData();
// check if data is the same
foreach($data as $item => $value) {
if ($this->data[$item] != $value) {
// save in database
}
}
}
}
You shouldn't necessarily sit down and choose a design pattern as in "okay, I'm going to implement a decorator pattern." Instead, you should design your code the way it's supposed to work, and the design pattern will develop as a result of that. It just so happens we have a lot of existing terminology that describe some common design patterns and knowing what they're called can make it easier to describe them.
At any rate, I would suggest you go up rather than down. Instead of extending Node and trying to force APIData in there somehow, you can have a separate object that is composed of Node and APIData objects and does its individual work through them.
When PHP 5.4 comes out with its traits, this will be so much the easier.
If we use type hinting, we can place an object mandatory:
public function myMethodThatDoFineStuff(MyObject $myobject) {
}
What if, we would like to place, not the all object but only some of it's attributes, to be mandatory ? Let's assume that our domain model will be better, if it better represents a certain domain.If this could make more sense on our business model (on our domain)? How should we do it ?
Our should we always place the ALL Object no matter what ?
EXAMPLE for clarification proposes:
Let's imagine that, in order to list books of a certain author we have this method:
public function listBookOfAuthor(Author $author) {
}
Now, let's imagine that the author object has 200 properties or so, BUT, in order to process the list of books, we only need their first and last name.
Should we receive the ALL $author object anyway ?
I would test for required properties in the following way:
public function listBookOfAuthor(Author $author) {
if (empty($author->firstName)) {
throw new listBookOfAuthorException('firstName must be defined');
}
}
If you find you're doing this lots you could write some kind of parent class that includes a method for checking properties are present.
What if, we would like to place, not the all object but only some of it's attributes, to be mandatory ?
Technically you can create an interface with only those some attributes the function expects. Isolated this might look a bit like overhead but Interfaces are worth to play around a bit with, more in the manual how they work in PHP.
Just because it could make more sense on our business model ?
I know nothing about your business model, so I can't say if it makes sense or not. But I thought you were asking a programming question not a business one.
Our should we always place the ALL Object no matter what ?
Then you'll loose type hinting but you will be able to pass any object. Depends a bit how strict you want to write your code. If you use interfaces you're pretty flexible when refactoring the code (changing concrete object implementations), as well as with the stclass object. However with the stdclass object the function needs to verify what it get's first before processing on the functions input.
Depending upon your schema, the method listBooksOfAuthor() (which looks like a method on a service object like BookService) could probably suffice with only an $authorId, not a full Author object.
But I think I understand the point of question. Perhaps the Author object is expensive to fully populate - say, from a method like AuthorService::getAuthorById().
For those circumstances when all you need is a modest subset of Author functionality, then perhaps you could create a distinct interface - maybe something like AuthorSummaryInterface - that reflects only those methods you need for those circumstances. Allow the Author object to implement that interface so that when you already have an Author object in hand, you can perform operations that only require that limited Author functionality. Alternatively, you could create a method Author:getSummary() that returns a concrete implementation of AuthorSummaryInterface. In this method, you could enforce your member requirements - must have a name, for exmaple - and throw an exception when those requirements are not fulfilled.
You might also create a set of methods - perhaps on an AuthorService object or an AuthorSummaryService object - that produce AuthorSummary objects. Then in those circumstances where only AuthorSummaryInterface functionality is required, you can create these limited functionality, less-expensive-to-create objects.
Just some ideas.
An instance of class A instantiates a couple of other objects, say for example from class B:
$foo = new B();
I would like to access A's public class variables from methods within B.
Unless I'm missing something, the only way to do this is to pass the current object to the instances of B:
$foo = new B($this);
Is this best practice or is there another way to do this?
That looks fine to me, I tend to use a rule of thumb of "would someone maintaining this understand it?" and that's an easily understood solution.
If there's only one "A", you could consider using the registry pattern, see for example http://www.phppatterns.com/docs/design/the_registry
I would first check if you are not using the wrong pattern: From your application logic, should B really know about A? If B needs to know about A, a parent-child relationship seems not quite adequate. For example, A could be the child, or part of A's logic could go into a third object that is "below" B in the hierarchy (i. e. doesn't know about B).
That said, I would suggest you have a method in B to register A as a data source, or create a method in A to register B as an Observer and a matching method in B that A uses to notify B of value changes.
Similar to what Paul said, if there's only one A, you can implement that as a singleton. You can then pass the instance of A as an argument to the constructor (aggregation), with a setter method (essentially aggregation again), or you can set this relationship directly in the constructor (composition).
However, while singletons are powerful, be wary of implementing them with composition. It's nice to think that you can do it that way and get rid of a constructor argument, but it also makes it impossible to replace A with something else without a code rewrite. Peronsally, I'd stick with aggregation, even if using a singleton
$foo = new B( A::getInstance() );
$foo = new B($this);
Code like this unfortunately does not match my needs. Is there any other way to access the parent object properties?
I'll try to explain why. We write a game software and some classes have very "unusual" dependencies and influence each other in different ways. That's why code sometimes gets almost unsupportable without links to parents in every instance (sometimes even several parents from different contexts i.e. a Squad may belong to Battle and to User etc...).
And now the reason why links don't satisfy me. When I generate an output for the client side, I use a kind of serializing objects in XML. It works very nice until it meets recursive references like those links to parents. I can make them protected, but then they loose their usage i.e. (dummy example)
$this->squad->battle->getTeam($tid)->getSquad($sqid)->damageCreature(...);
The other way - to implement serialization method in every serializable class and call it inside serializer like this:
$obj->toXML($node);
$this->appendChild($node);
but that's a lot of stuff to write and to support! And sometimes i generate the objects for serializer dynamically (less traffic).
I even think about a hack: to "teach" serializer to ignore some properties in certain classess )). Huh... bad idea...
It's a long discussion, but believe me, that Registry and Observer don't fit. Are there any other ideas?