|
|||||||
New to SitePoint Forums? Register here for free!
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
What's so good about OOP?
Now, in Perl or PHP, OOP is nothing more than having subroutines and variables separated into a different file (or module). I really don't see the point of declaring a package or class in Perl and PHP respectively.
The only difference I see is that the methods can access attributes declared outside the methods itself and within the class or package. But besides this, I don't see any benefits of using OOP. Maybe someone can quote me with a few examples? You don't have to quote complex ones like databases. Just a simple example like the classic "hello world" will do. Many people told me that with OOP, you can add functions to a script very easily. I don't know why. |
|
|
|
|
|
#2 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
The stock answer is: Abstraction, encapsulation, inheritance and polymorphism.
As PHP is OO capable but not really OOP, you can usually program a solution faster using a procedural approach. In the long run, however, by taking an OOP approach and putting in the time to "objectify" the problem(s) at hand, you'll have a more robust and extensible application. I hear that PHP 5 will go further down the OOP road, and I hope they do. I for one would like to see an OOP paradigm approximating that implmented in JAVA. To start, adding multiple constructor support to PHP-Objects would be a great. As ever, Pete Last edited by phpPete; May 12, 2002 at 06:16. |
|
|
|
|
|
#3 |
|
SitePoint Enthusiast
![]() Join Date: Apr 2002
Posts: 54
|
I would argue that as it stands at the moment OOP is not all that useful for short or even moderately sized scripts; however I can understand where it would come into play for larger projects. Apart from the standard OOP efficiencies, the extensibility and manageability factor would probably come most into play here - code a class definition into a separate file, then just drop in a require_once("whatever.php"). Easy!
|
|
|
|
|
|
#4 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
...and I would agree. Since when the scipt finishes executing PHPs' work is completed til the next script. To truly make PHP an 100% OOP language would, I beleive, be a detriment to its speed and be a big hit in development time for us developers.
Where OOP can be employed is for code that we reuse, and that is how I've gone about it in my work. |
|
|
|
|
|
#5 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
Why don't you guys quote examples? I've heard from many people the benefits, but I just don't see them. I really need examples to understand........
Ok, you guys say OOP code is more manageable, right? Any example to illustrate this point? Also, OOP code can be extended easily? Any examples? |
|
|
|
|
|
#6 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
Here's a class definition for adding menu items to a DB:
PHP Code:
PHP Code:
PHP Code:
That goes to code reusability. Cheerio |
|
|
|
|
|
#7 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
But what I don't understand is, why must I do it in OOP? I mean, I can achieve the same convenience with procedural. I just have to declare normal functions on a separate file without declaring them in a class. Then I just "require" the file. By doing this, I'm also reusing my code, aren't I?
Another thing. I've heard from many people that by using OOP, you write shorter code. I don't really agree. You see, you just said that the class definition is intensive, so isn't it still the same? Sorry, but pls don't take offence to any of my words. You see, I want to learn. When I want to learn, I will make sure that I understand 100%. I counter your arguments so that I have a higher chance of learning. |
|
|
|
|
|
#8 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
You can do much if not all with functions and includes/requires etc. It's very modular. And in that case you're only writing the function once then including as needed. One can argue that procedural vs. OOP is a matter of taste.
When you define a class, you're modelling an Object, not merely a behavior. Functions go to behavior. So a class has properites, as well as behavior ( functions ), thus a class, when well designed is more versatile. Either way you look at it, you're still going to have to code a fair amount. It's that with OOP, you're localising it within the class, not the include file. |
|
|
|
|
|
#9 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
So when should I consider using OOP, and when must I avoid it?
|
|
|
|
|
|
#10 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
That's a good question, as very often you can code something rather quickly in a procedural manner. i'd say when you are working on an application and you determine that certain charactersitics of the application will be re-used, and have multiple properties, then a class is a good way to go.
For example, if you're building an application that has members, then each memebr has basic characteristic, or properites: Name, gender, email, whatever you like. Here would be a good candidate to make a class definition for members. An excellent book on Object Modelling is "Beginning Java Objects" from Wrox Press, written by Jaqui barker. The first 1/3 of the book is devoted to modelling objects in such a way that any language that supports OOP can be adapted, not just JAVA specific. |
|
|
|
|
|
#11 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
Going into your members example, are you trying to say that using OOP is enabling you to write neater code? Like your example, all properties are stored in an object, which is neater, compared to many variables.
|
|
|
|
|
|
#12 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
That's one way of looking at it. But in essence, think of an object as a variable on steroids...you're making one definition with whatever properties/methods you think you'll need, then each object instantiated from that class has all those properties and methods inherent to it. Further along then, you make objects which inherit from other objects, and in doing so, you have all the methods/properties of the parent object, as well as any new methods & properites defined in the child objects' class definition.
|
|
|
|
|
|
#13 |
|
SitePoint Enthusiast
![]() Join Date: May 2002
Posts: 75
|
Ok, thanks for all replies.
|
|
|
|
|
|
#14 |
|
SitePoint Evangelist
![]() ![]() ![]() ![]() Join Date: Oct 2001
Posts: 592
|
And here's another one
.One of the reasons that procedural programmers are hard to convince that object-oriented programming is so great, is that the examples given aren't very spectacular: most of them can be rewritten easily in procedural code. Also, much of the so-called OOP code out there isn't object-oriented at all. The PEAR library for example, is in fact not a real object-oriented library, even though the developers claim it is. (Don't worry, I'll explain my reasons for saying this below .)The biggest advantage of OOP is re-use. Re-use comes in three flavors (mostly), but only one is used a lot, while the second and third are almost never used. PEAR, for example, uses only two flavors (and the second flavor minimally). So what are these flavors of re-use? Well, here they are: 1. Object instantiation This is the easiest and most popular form of re-use in OOP. phpPete gave a good example with his menusystem, so I won't give one here. You write a blueprint for some type, and you can reuse it over and over again simply by instantiating it (creating a variable and calling methods on it). In procedural programming you can achieve the same result by writing a module: a set of functions operating on the same datastructure. There is no advantage whatsoever in using OOP instead of PP for this type of code, except that OO-addicts (like me) say that using a class instead of a module makes the code easier to read (Example: '$database->query($sql)' instead of 'query($database, $sql)'). 2. Class inheritance The second form of re-use in OOP is class inheritance: given some class, you 'extend' it, adding new features or overriding existing ones. Inheritance comes in many forms, and I'll briefly describe three of the forms here, comparing each of them to procedular programming. - Abstract base classes An interface (or: abstract base class, or even: virtual base class) is a class that defines a number of methods, but doesn't implement them. A subclass of the interface class must implement all methods to be a valid interface implementation. For example: PHP Code:
The advantage of this kind of inheritance (and re-use) shows when using a strongly typed language (Java/C++). If I were to implement a subclass of class Database, the interpreter (or compiler) makes sure I do not forget to implement some method, that all methods have the right number of arguments, all of the right type, and that every method returns a result of the right type. There is no such thing in procedural programming, and the result is that programmers have to write code according to some long and dull manual. With OOP, you can throw away the manual, and trust your compiler to do the dirty work for you. Because PHP doesn't explictly check types, writing interfaces isn't as useful as it is in Java or C++. That isn't to say it has no use at all. You can still write an abstract class, and use that as the guidelines you must follow if you want to implement the interface (instead of the boring manual). Also, you can put a 'die("Method not implemented!");' in every method in the interface, so that when you call that method on an object with an incomplete implementation, the program halts immediately. - Class extension Say you have some procedural module, but it doesn't quite do what you want it to do. If the module consists of many functions, you might be able to replace a couple so that it does. However, if the old module must be maintained at the same time, this means that you have to write a new module with all the same functions as the old one. In the new module, every function simply calls the equivalent function in the old one, except the ones you want to redefine. The result is that you end up with large blocks of code that do virtually nothing. With OOP, you can achieve the same result by simply writing a subclass, and replacing only the methods you want to replace, keeping all other methods intact. The beauty of this is that the subclass is easier to write (less to type, so less chance of bugs) and easier to understand: only the code that adds something new must be written. The PEAR library implements this kind of re-use a lot. Take a look at classes DB_mysql, DB_pgsql and so on. Class DB_common is the superclass of both classes, and defines basic methods. The two subclasses override only the necessary methods to get their work done. (But one of the biggest problems of PEAR is that almost every method of class DB_common has to be overridden to get it working. That's a clear sign of bad design!) - Template classes Most procedural programmers are familiar with callback functions: you write some function that takes as an argument (a pointer to) a function, and calls that function with yet another set of arguments. Those who ever did that in C will hopefully agree with me that it's pretty hard to do, because the code looks frightening (unless you're a C-guru), and it's easy to make mistakes. As an example, take a function that implements 'bubble sort' on arrays with value of any type. To be able to sort the values, the function needs to call a user-specified function that compares two values. If the first value is bigger than the second, the function returns true, meaning that the values should be swapped: PHP Code:
PHP Code:
PHP Code:
Sadly, I haven't found any occurrences of hooks in PEAR. Draw your own conclusions from that... There are more ways to use inheritance, but let's keep it at the three mentioned. I'll now continue with the third flavor of re-use in object-oriented programming: 3. Object composition This is maybe the most powerful and beautiful application of OOP, but as it's also the most difficult one, almost nobody uses it. The idea behind object composition is that you implement classes that don't do a single job completely by themselves, but require additional classes to make them complete. That makes it easy to mix and match object of various types to get completely different behavior from the same classes. As you probably expected by now, PEAR does nothing of the sort. As a simple example, consider again the bubblesort algorithm given earlier. The BubbleSort class looks a bit weird, because: - I have to instantiate an object just to run the algorithm. However, the class has no member variables, so why would I need an object? - When I override class BubbleSort (as in BlobBubbleSort), there is a potential danger that the algorithm itself can be overridden as well. This is not a clear separation between the main algorithm (bubble sort) and the specialized behavior (comparing two objects) To solve this, I implement the algorithm in two classes, instead of one: PHP Code:
Object composition is something you just can't do without, as it allows you to abstract from the problem your working on, and lets you write code in layers. It's almost a requirement for a proper object-oriented programming library to support object composition. (Did I mention already that PEAR doesn't have this? Ah, never mind...) Final remarks The best object-oriented programs aren't the ones that use only one or two of the techniques I mentioned here, but the ones that combine all of them. For example, consider I write an interface 'Object', that defines a method 'getValue'. I use this class as a baseclass for all classes in the system to store all sorts of values. By writing one single class 'ObjectCompare' and implementing the simple method 'compare' in that class, I can instantly sort arrays of any kind of object! Thus, by combining inheritance and object composition, I can do a whole lot with very little code. Achieving this same result with procedural code not only requires more code, but also results in code that's difficult to understand. To end this long (and boring) post, consider a program I just wrote for one of the web sites I'm working on. The program reads a text file containing a menu system, and prints it in nicely formatted HTML. The file it reads is the following: PHP Code:
- Each line in the file must be accessible as an array. The first line of the file contains the key. Thus if the first record would be in the variable $record, the value $record['name'] would be 'SitePoint'. - The complete file must be stored in memory, and each record must be accessible as described above. - The records in the file must be traversed. - Each record must be printed in HTML - The records must be ordered on category To be more specific, I want to map the above text file to the following HTML: PHP Code:
PHP Code:
Let me try and explain what it does, from the outside to the inside: - Class Loop is a simple class that uses object composition. Its sole method 'run' requires an 'iterator' and a 'loop manipulator' as its arguments. The method implements a simple iteration, that is influenced by the manipulator. - Class DataFileIterator implements the 'Iterator'-interface for DataFiles. There are also iterators for trees, query results, built-in arrays, strings, you name it. They can all use the Loop class. - Class DataFile stores file-based tables in memory. It allows access to each record in the file. However, it doesn't know how to parse lines in files itself, so it has to be passed a DataFileReader class that does that specific job. - Class MenuPrinter is a 'loop manipulator' I wrote earlier that generates the required HTML. Although I haven't included the code for that class here, as it would require even more explanation of the classes I use, please believe me when I say that it is an extremely simple class. What if the text files have a different format? Well, then I replace the DataFileReader. What if I need to print the menu in a different layout? Well, then I replace the MenuPrinter. What if I stop using text files, and want to use a real database instead? Well, then I simply execute a query on a database and use a QueryIterator to process the results, like this: PHP Code:
Vincent |
|
|
|
|
|
#15 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
KILLER EXAMPLE!
|
|
|
|
|
|
#16 |
|
SitePoint Guru
![]() ![]() ![]() ![]() ![]() Join Date: Aug 1999
Location: B-Town
Posts: 977
|
However, PHP has not yet seen the full potential of OOP. Also, there is a lot of overhead with OOP in PHP right now. Hopefully, this will change as if you know what you are doing with OOP, you can write your code a shorter than if you were writting it in a procedural fashion.
The main advantage of OOP is that when you write a class, you can reuse it over and over again, because you are completly separating your code in between objects. -cARL |
|
|
|
|
|
#17 |
|
What?
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Oct 2001
Location: Whistler BC originally from Guelph Ontario
Posts: 2,187
|
I stand on the positive side of oop. I have spent a lot of time studying the concept and can promise you that I increased my production time by at least 3x. I also increased readability of the code and extensibility. That said it isn't really something you can explain to someone because procedural style programming 'CAN' do it. Oop doesn't do it better but differently. The way I think is very organized and very block oriented. Oop suits me perfectly.
Like I said I believe oop is a line of thought. Both systems work and one may be more efficient than the other but really if you don't get oop you won't be able to use it properly. ![]() As for the overhead and slow down of oop. I have programmed in both styles and don't see the difference. If there is one it is of no consequence in the newest versions of php. This may have applied in pre ver 4 though. |
|
|
|
|
|
#18 |
|
Super Ninja Monkey
![]() ![]() ![]() ![]() ![]() Join Date: Dec 2001
Location: Sioux City, Iowa
Posts: 709
|
wow voostind you should write some tutorials or an ebook or something! all your posts on layering and OOP have totally blown me away and made me rethink the way i write PHP scripts.
|
|
|
|
|
|
#19 |
|
Making a better wheel
![]() Join Date: Jul 2001
Location: Missouri
Posts: 3,426
|
i'm trying to decide whether to use OOP for a project that i haven't really started yet (so i can still do it right, from scratch
). now, i'd say the only thing that's holding me back is the speed concern if OOP is slower. that's just because i hate having anything slower than it could be. have any of you benchmarked procedural and OOP versions of the same, real-world code? i just made this as a test on my P3 800:PHP Code:
the second takes ~4.9ms of course that's an extremely simple function, but i was just trying to get an idea of the OOP overhead. so it looks like less than 2ms for 1000 OO operations. i assume that accessing variables in a class would also be slightly slower than accessing "regular" variables? i like the fact that with OOP i can, i think, eliminate having to use `global $var;' to access variables between functions as i would have to with procedural. also, i was wondering since i've never used OO before, what would be the best way to make like a $db object available in another class' methods without having to pass it? would you do something like this: PHP Code:
i think you were explaining this in another thread, voostind. or would you have something in AnotherClass that creates the $db object, and then access it as, i guess, $foo->db->query()? or is that not a good idea? don't laugh! i don't know anything about this and want to know the best way to do it. others may be wondering the same thing. ![]() |
|
|
|
|
|
#20 |
|
What?
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Oct 2001
Location: Whistler BC originally from Guelph Ontario
Posts: 2,187
|
I think the speed difference starts to be even less of an issue with larger projects. I think if you compared say a cms built on good procedural compared to oop the difference would be insignificant
![]() $foo->db->query() That is similar to the way i design my classes. But according to Voostind current post this could be further optimized by something like (and I probably have this wrong as I am trying to grasp that level of oop design. $test=new Test(new Db("table_name")) Then you could have something like class Test { function Test($dbcnx) { $this->dbcnx=$dbcnx; } } Then later in that script you can further access the db class by referencing the $this->dbcnx->query(); for example. I think I have that right or at least close. Advanced oop tachniques are still a little over my head. And fully grasping the idea of layering in applications is also a little tough. But heh thats what hitting the books is suppost to do right ![]() |
|
|
|
|
|
#21 | |
|
SitePoint Evangelist
![]() ![]() ![]() ![]() Join Date: Oct 2001
Posts: 592
|
Quote:
Okay, let's talk about databases .The Database interface I gave in my previous post is actually more or less the interface (give or take a few methods) I use every day. As you can see, there is no way to process some kind of query result. However when I do this: PHP Code:
PHP Code:
Now, classes Database and QueryResult are both interfaces, so they don't do anything by themselves. If I want to use some specific database, I have to implement both classes, as in MyDatabase and MyQueryResult for MySQL, and PgDatabase and PgQueryResult for PostgreSQL. The philosophy behind both interfaces is that every class should do what it does best. Class Database knows about connecting to databases and executing queries on it, so why bloat it with code to process the results from those queries? That's a whole different ballgame, so that's why I wrote the QueryResult interface. If you compare this to PEAR, you'll see the following: - Class DB_common (and thus classes DB_mysql, DB_pgsql, and so on) have many methods. It can be used to connect to databases, execute queries, process the results in these queries, and handle transactions (and that's not all!). - There is a class DB_result, but it's not meant to be subclassed. When using this class to process query results, it internally calls the query handling methods in the database class. Now what if I want to do something like this (and I do regularly): PHP Code:
Given the query result $books above, I can print booktitles like this: PHP Code:
In my previous post, I told about class Loop, which implements loops on iterators. Iterators are higher-level, generic objects. All iterators have the same interface, so I can use the same loop for arrays, strings, trees and query results. The iterator for QueryResult-objects looks like this: PHP Code:
To print book-titles, I can now write this: PHP Code:
PHP Code:
1. prepare(): is called right before the first item in the iteration is processed 2. between(): is passed in between every two items, thus not before the first or after the last 3. current(): is called for every item 4. finish(): is called right after the last item in the iteration is processed If I were to print book-titles, I now have to write a manipulator. To make life easy, I can write this manipulator as a subclass of class LoopManipulator, that implements all four required methods as empty methods. For example: PHP Code:
PHP Code:
If you examine the code above more closely, you'll see that the variables $result, $it and $manip are all temporary: once the loop is completed, they aren't needed any more. The question then is: why create them at all? Thanks to the design of the various classes I can write the code above like this: PHP Code:
To answer the question "Why is using manipulators a good idea?": - There is now a clear separation between the algorithm (the loop) and the behavior of the algorithm (printing booktitles). In other words: object composition. - The algorithm (the loop) is implemented just once in a generic way, instead of many times, specialized for specific problems. - As the manipulator is a class, I can reuse it by writing subclassing or wrapping. - An intelligently written manipulator can be reused for other loops. - Layering is supported 'out of the box' To end this post, I'd like to remind you that the example I've used here is pretty simple, and therefore may lead you to think that the various classes are bit 'over the top'. In larger systems they certainly aren't, I can vouch for that! Also, by using a set of compact and efficient classes instead of large, bloated ones (PEAR), I find no impact in execution speed whatsoever. But that's just my experience of course ![]() Vincent |
|
|
|
|
|
|
#22 |
|
SitePoint Zealot
![]() ![]() Join Date: Jun 2001
Location: UK
Posts: 138
|
Vincent, I'm learning to love the wooshing sound that your posts make as they go waaaaaaay over my head! LOL!
![]() Seriously, though - I'm a PP man myself.. never quite grasped the OO approach in my time at Uni, and it cost me dearly. (my degree, as it happens!) I reckon if any of my lecturers had half the talent for breaking stuff down as you do, that wooshing sound would be the sound of my brain grasping the concept. Nice to see Larry foxed for once - you guys keep at it; I'll follow along. *scrolls back up the page and gets reading* |
|
|
|
|
|
#23 |
|
gingham dress, army boots...
![]() Join Date: Apr 2002
Location: Salford / Manchester / UK
Posts: 4,856
|
voost, at last a description of OOP in PHP that makes me strongly consider at least dabbling with it. i can see the logic behind it, and yes, if you look at it that way, it does make a lot of sense indeed. i was under the (mistaken, admittedly) impression that OOP in PHP == PEAR, and what kept me from playing with it was indeed the bloated "one-size-fits-all-or-else" approach of all those classes. if i now start going OO and flood this forum with silly questions, remember: it's your fault for starting me down that path
![]() |
|
|
|
|
|
#24 |
|
What?
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Oct 2001
Location: Whistler BC originally from Guelph Ontario
Posts: 2,187
|
Thanx again voo. I think I have more posts by your printed out than anyone. You have also (indirectly) convinced me to go and grab some cbt's on advanced oop. I thought I had a good understanding of it but realize I have a 'good' understanding, I want to understand more
![]() Again, muchly appreciated on the fantastic artical. |
|
|
|
|
|
#25 |
|
SitePoint Addict
![]() ![]() ![]() Join Date: Feb 2002
Location: Atlanta, GA
Posts: 341
|
I would also refer people to this article/tutorial on the ZEND WebSite.
|
|
|
|
![]() |
| Bookmarks |
«
Previous Thread
|
Next Thread
»
| Thread Tools | |
| Display Modes | |
|
|
|
All times are GMT -7. The time now is 06:56.





.


i don't know anything about this and want to know the best way to do it. others may be wondering the same thing. 


Linear Mode
