Re: Some PEAR remarks

From: Date: Sat, 20 Apr 2002 07:41:21 +0000
Subject: Re: Some PEAR remarks
References: 1 2 3  Groups: php.pear.general 
Request: Send a blank email to pear-general+get-1228@lists.php.net to get a copy of this message
On Fri, 2002-04-19 at 12:48, Vincent Oostindie wrote: > On Thu, 18 Apr 2002 13:11:40 +0200, Stig S. Bakken wrote: > > Public properties are useful sometimes, I'm not in the "encapsulate or > > die!" camp, even though I always almost encapsulate. > > In my humble opinion: that's just too bad. Maybe when implementing an > application I could slightly agree, but when implementing a library - > intended to be used by many, many programmers you don't know - you should > definitely encapsulate everything. But that's just my opinion :-) > > > The PEAR class is really not a base class like Object in Java, but a > > place where we can emulate functionality that is still missing from PHP > > (such as destructors and exceptions). > > Alright, I understand that now. But it could be nice for a programmer to > be able to choose: destructors only, error handling only, or both. > > > PEAR is very much geared towards ZE2 and PHP 5. PEAR errors are a poor > > man's exceptions, and they will be replaced completely by exceptions > > when using PEAR with PHP 5, so using them will become easier. > > I've read the ZE2 plans, and I'm anxious to see them implemented! > > >> Class DB is a class with static methods only, and the two most > >> important ones (factory and connect) either return an object of the > >> requested type, or an instance of class 'PEAR_Error'. Again, I think > >> this is not a good separation of 'normal' code and 'error' code. > >> Also, > >> whenever some code calls one of these methods, it should always check > >> whether the object returned is the one they wanted, or something else. > >> This raises a question: how often is this done by your typical lazy > >> programmer? And what about production-state code? That kind of code > >> doesn't contain any programming errors, so then there's no need to > >> check for them. > > > > Uhm, programming errors? PEAR can't help you with those I'm afraid ;-) > > But it does! When you supply class DB with a 'hard-coded' DSN that's > incorrect, class DB will return a PEAR_Error. Maybe it's not a > programming error at the lowest level, but it's still a programming error > in my book :-) > > >> Much of the error handling can be simplified by introducting 'Null' > >> objects. These are objects of a class that simply do nothing. For > >> example, you could have a class DB_null that is just like any > >> DB_common-derived class, and is returned whenever a requested database > >> class doesn't exists (when calling DB::connect). It simply returns > >> default values from its methods instead of doing anything useful. This > >> trick makes using the library a lot easier, and of course it applies to > >> much more than just the DB class. > > > > Using existing values for errors is very difficult in a large scale. > > What if you actually want to return NULL from a function? There are no > > simple, scalar values available for this, that's why we use objects. > > I think I didn't make myself very clear: I didn't mean the value 'NULL' > should be returned, but a 'Null Object' instead. I'll explain it below, > but I have to say first that they are mostly useful for 'default values' > and not for error handling. Doing that is probably not a good idea, > contrary to what I said first... (Sorry!) > > Imagine you have a class User that stores information on the current user > in a web application. However, this user is only available if he/she > actually logged in to the system. This often leads to code like this: > > // Print the name of the user > if (!$user->isLoggedIn()) > { > echo $user->getName(); > } > else > { > echo 'none'; // or something > } > > These if-statements tend to be repeated all over the code, in various > guises. An elegant solution is to create a NullUser, which could look > like this: > > class NullUser extends User > { > function getName() > { > return 'none'; // or something > } > } > > Now, at the start of the application, it is checked exactly once if the > user is logged in. If he/she is, a normal object of class User is > instantiated (or restored from a session or whatever), or else an object > of class NullUser is used. This greatly simplifies the remainder of the > code, as you'll hopefully agree. > > Often, these 'null objects' return other null objects. Imagine class User > has a method 'getFavorites' that returns an object of class Favorites with > favorite products in the web application specific for that user. (Like > Amazon.com can store your personal book list.) Class NullUser would likely > implement method 'getFavorites' to return another an instance of class > NullFavorites, if class Favorites can't be used for that. > > It might make sense to implement all null objects as singletons. > > >> If I - as a user of the PEAR library - wish to use PEAR to create a > >> connection with a MySQL database, the following files will be included: > >> 'PEAR.php', 'DB.php', 'DB/common.php' and > >> 'DB/mysql.php'. That's 793 + > >> 874 + 1281 + 847 = 3795 lines of code (in PHP 4.2RC4). For fairly > >> trivial tasks like making a database connection and executing SQL > >> queries, I think that's a bit much... > > > > I agree, there's too much code in there right now. > > Yeah! I finally convinced someone! :-)) > > > When user-space overloading and aggregation is finally declared stable > > in PHP, DB will be rewritten to use it. I plan to partition out (and > > auto-load) big chunks of code that will make the basic connection class > > much lighter. > > But that doesn't really solve the problem, does it? The code will still > be there. > > As I said in another post in this thread, I think classes DB and > DB_common are too feature-bloated. Methods like 'fetchOne' and > 'fetchAll' simply shouldn't be there, because they do not add a new > feature to the library; they only combine a couple of existing features > to make using them easier to use. That kind of code shouldn't be in a > library, or at least not at that level. Not in a library? Then where should it be? They certainly are features in a library, because they provide a quick and easy way to do simple queries, which makes programmers more productive. > > As with encapsulation, I don't think people should be religious about > > re-use. Sometimes, avoiding too many dependencies is a valid tradeoff > > for code reuse. Re-use is good, but not something to get religious > > over. If you can avoid installing/using a whole new package with 5-6 > > lines of code, those are well worth it from a maintenance standpoint. > > When writing an application, you're right. A library or a framework is a > whole different ballgame, not comparable in the slightest to implementing > an application. If a (big) library isn't able to re-use itself in its > implementation, it generally stinks. You might want to read up on some > literature on building libraries or frameworks to see what I mean. I > don't mean to say that you don't know what you're doing, certainly not! > (Who am I to say that?) It's just that writing a library is a very large > and complicated discipline, too large for me to explain here. (And I > don't consider myself qualified for the job anyway.) > > Also, enabling re-use isn't the same as adding many dependencies, as you > imply here. It's perfectly possible to re-use a lot of code without > having too many dependencies. Finally, re-use is definitely something to > get religious over when you're writing a library! In an application, > re-use is nice to have, but not a requirement. In a library (or > framework) it certainly is. I think we have different perspectives of this: PEAR is not a huge library where you install everything at once. It is a collection of independent packages that may and often do use functionality from other packages. When a package does this, it is expressed through a dependency declaration that is checked during install. If you have ever used Perl's CPAN, you may have experienced one of the extreme consequences of dependencies gone hay-wire: if you have an old version of Perl and want to install something that uses only part of a big, bleeding-edge-type of package (libwww-perl for example), you end up reinstalling Perl. This is extremely annoying, and I don't want to put PEAR users through the same thing. So IMHO, re-use has a higher cose if it requires installing a new package (because that may possible introduce other problems, as well as affect complexlity and maintainability). But again, in general re-use is good. - Stig

« previous php.pear.general (#1228) next »