I'm just getting into PHP OOP and I'm unclear on what properties I need to declare at the start of a class.
Do I declare properties:
A: that are arguments for methods?
B: are not arguments for methods but are still within a method?
C: that are returned from a method?
Edit For Example
Here's an example userclass I'm trying to create
class user
{
public function selectMember($username,$password)
$query = "SELECT * FROM users WHERE username='$username' && password='$password'";
return $query;
}
So I would have to declare $query only at the top of the class?
The way I think of these things is that an object is a code representation of a real life object (duh). The car example above is a good one. For most real life objects there are attributes and actions. If our object is person, it will have attributes like name, height, weight, hair color. Then, our person will have actions, like run, sleep, eat.
The actions will be methods and the attributes will be properties. Properties will either be used in the actions or by other parts of the program which need to check the state of your object, IE, another part of your program asks the person how tall it is right now.
In most cases, return values and arguments will not be properties. A notable exception would be arguments you use to instantiate an object, as those will typically be needed by your other methods. As far as variables used within a method, these should be properties if they define the overall state of the object, but if you are creating a variable, like a counter, inside your method, that is just needed to accomplish the goal of the method, it doesn't make sense for it to be a property of your object.
I would start out by erring on the side of fewer properties. If you get to a point where you need a property to accomplish something, then create it. I wouldn't create them until I have a direct need. This way, you'll begin to get a feel for what properties an object will need in order to function logically.
I hope that makes a little sense.
Properties are pieces of data about the object. For example, to take the classic car example:
The car's color, make/model, year, etc. are all properties of the car.
There may be a method StartCar that requires a Key object to start. The car does not have a key, therefore the key is not a property -- it is a method argument. But the car does have a lock that is capable of validating a given key. The argument and the property work together to perform the action (or, in this case, validate the action).
Each instance of the car class may have different values for these properties.
If you need specific help deciding what to make into properties, we will need more information about your specific requirements.
Php.net have a real good documentation about PHP OOP
It's pretty much your choice, according to the best answer in "When should I declare variables in a PHP class?".
Related
I document model classes (in PHP) with Doxygen. I am using Idiorm & Paris as an ORM and I would like the dynamic member variables (coming straight from the database) also to appear in the generated documentation.
Example: I have a model Group with some methods like isMember() or users() documented with Doxygen. In the database I have a table group with a field code among others. In Idiorm & Paris I can access it from a Group instance $group like this:
$group->code
How can I document code in Doxygen?
Edit: This question is similar to How to document a variable that isn't really there in Doxygen?, but it's about dynamic members, not about variables.
Edit 2: I am unsure about the right terminology. It is a dynamic member variable or a dynamic property?
Something I usually do when setting up models for which I know they will contain certain bits of data is setting the variables in the model definition. This makes it easier to see what kinds of data I can expect with the model.
I have no experience with Idiorm nor Paris, but it is something you could try. Documenting the variable is then very easy, because it exists.
Is it impossible to document non-existant class variables in Doxygen? I tried a naked
/** #var User::email string
* Email address
*/
without a corresponding $email; member variable in the class, but Doxygen valiantly ignored that. I didn't find a command or something to force a documentation of a missing artifact.
Therefore I experimented with creativedutchmen's suggestion, however Paris does not cope well with already existing member variables, because – I think – the PHP magic method __get() does not get triggered anymore. I see three possible fixes:
unset() the documented member variables in the constructor. With get_class_vars(get_class($this)) this could be done in a parent class. Because my model classes all inherit from a parent class, this would be relatively straightforward.
Modify Paris to ignore already set member variables, but I do not see how without unset().
Name the member variables slightly differently, like appending an underscore, so they don't conflict with the dynamic variables.
Horrible kludges. To do something at runtime or have additional members to make documentation possible? No thanks.
I decided to leave the situation as-is and document the model factory methods carefully instead. Most of the time the factory methods contains as parameters the class variables to be able to set them. And even if the factory method does not set all class variables, it is possible to document the missing variables in prose. The class documentation is also a good alternative.
I award the bounty to creativedutchmen because of thinking out of the box, even if it didn't help me in the end and because I don't want the reputation points to get lost.
tl;dr
Don't kludge. Document dynamic member variables in the factory method or in the class overview.
Ok, I couldn't insert the overview image, but I'm required to create a PHP app for my studies, it must allow student to register, and the administrator to edit course and student info.
We are not required to code it in an OOP style, but since its the best programming practice to code in OOP, why not learn OOP from the beginning.
I'm a beginner but I know the basics about OOP, classes, inheritance, setters and getters and all that cool lingo, but I'm struggling to decide which parts of this app should be objects, should I make course and student classes or add, edit and delete classes? Any advice on how to approach and visualize such a problem would be appreciated.
Very roughly: This is how I would do it:
Store your data in SQL or XML. You will need two SQL tables, one for Students and one for Courses. You can use one XML file containing all the data, or you can use two files (which I recommend).
Create a class called, for example, dataItem with a property like '$arr_fields' corresponding to a single data record (a single row in a SQL table, or an XML record).
The dataItem class should have the following methods (all public):
loadFromSQL() (or loadFromXML())
saveToSQL() (or saveToXML())
add(), edit() and delete()
a view() method using HTML
These methods are obviously used to read and write data between the SQL/XML data and $arr_fields of the class, and to display the data in $arr_fields. The keys of $arr_fields are the SQL column names (or XML tag or attribute names) for the specific SQL table.
Try not to call loadFromSQL() or saveToSQL() in your constructor or in any of the other methods which are used to modify only the class data. Keep these actions separate. EDIT: This is a personal preference which helps me to keep track of the state of my objects.
Create Student and Course classes that extends the dataItem class.
You can override methods, for instance the view() method, inside your extended classes if you need to.
Then you can call the methods in Students and Courses from an Admin object (like rcdmk suggested) or maybe from StudentFolder and CourseFolder classes whose view() method contains buttons for the actions that need to be performed. (Let StudentFolder and CourseFolder extend a Folder class that you create).
UPDATE:
For example: If your primary key in a SQL table is id, then dataItem's loadFromSQL($id, $tablename) should set $arr_fields so that its keys are the column names and it's values are the values from the row whose primary value is equal to $id.
In Students, you can then override loadFromSQL() as follows:
class Students extends dataItem {
// other attributes
public function loadFromSQL($id) {
parent::loadFromSQL($id, "Students");
}
}
EDIT: On reconsideration, it might be better to set $arr_fields["id"] = $id and also set $tablename with the constructor for dataItem - then you never have to override loadFromSQL() or specify parameters for it. loadFromSQL() should then load the record if it exists. saveToSQL() should save $arr_fields in SQL if $arr_fields["id"] is set and create a new record if it is not set. Anyway, you must find a consistent way of interacting with the data which works for you, these are just possibilities.
However, if you are not experienced with OOP and SQL or XML, you might be opening a can of worms for yourself and it might be better to just do your assignment using functions only and php arrays for your data. Unless you have some time to learn...
From a simple perspective:
Abstract the main objects as classes and use methods for actions of this objects:
Student (object) are deleted (action) by the Admin (object), so
Admin class will have a deleteStudent method, because Admin deletes Students.
Another aprouch is to concentrate all Student related actions in the Student class:
Student class will have a public delete method that Admin can use.
Anyone that think this in better ways of explanation can edit this wiki.
Think about which aspects of your system are actually objects, you know, something you can do something with. The methods are what you do to the objects. So, you're on the right track with course and student classes, and add, edit, and delete would be methods of those classes.
But don't get too bogged down with it. If it's not your core assignment objective, you could quickly get in over your head by trying to do everything exactly the right way. If you can formulate a clear way to get to where you need to go, then go for it, if it seems confusing, back off it a little and learn some more.
You say that you know the basis of OOP, however you ask whether you should create Course, Student classes OR Add, Delete, Edit classes. Well maybe there are other practices, but I guess the most popular one and the only I am aware of is to use nouns as classes and verbs as their methods. Hence, intuitively there is something wrong with class "Add" or "Edit". What I would have done if I were were, is to think of all "entities" that might be considered an object - like Student, Course, Lecturer, Class (Room) and depending on how advanced your model should be you can add more like Building etc. Then try to implement basic things like creating new student, registering for a course, associating teacher with a course etc. Once you have it in place and IT IS WORKING you might want to add advanced things, like inheritance. For example you might want to say, that both Teacher and Student are a Person so you might want to create such abstract class and use inheritance.
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.
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.
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?