SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 45

Thread: PEAR QuickForm

Hybrid View

  1. #1
    SitePoint Zealot
    Join Date
    Sep 2002
    Location
    Calgary
    Posts
    160
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PEAR QuickForm

    I am currious as to how people find using this module. Does anyone fine it usefull and if so does anyone have any good examples to go with.

  2. #2
    SitePoint Enthusiast
    Join Date
    Jan 2003
    Posts
    60
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    using QuickForm

    Actually, I am realling dying to get Vincent's (voostind) input on this library since his points out that a lot of PEAR's libraries are bloat and not true OO design.

    It appears to me that QuickForm is (comparingly) proper OO design. The concept is to create a form, which has elements. These elements are all derivatives of the HTML_Common element which has a tag name, attributes and possibly a text node content. You build the form by adding elements to it using the extended objects for each form type. It has extensibility, because you can define your own type by extending either the common form element or a more specific form element. Each element has a toHtml() method as well as generic and specific methods for modifying its properties. The form has methods to add rules, etc.

    The only downside of QuickForm is that it assumes you want to use a basic internal template when you output it. It would have been better IMHO if QuickForm could allow you do use an include file like Vincent's templates (a php file) that would be used to build out the form. My collegue and I added a method to each element called 'renderElement()' which prematurely spit out the element which we then stored into an element array. Then we would include a file that used this array to populate our PHP template page which would be buffered, then dumped back into the addData() method of the form and then the form was outputed. It would be better if I included some code. Here is what we would do:

    PHP Code:
    <!-- mypage.php snippet -->
    <?php
    $form 
    =& new HTML_QuickForm('formName''POST''index.php');
    // throw away the QuickForm template junk (Vincent won't like this)
    $form->clearAllTemplates();
    $form->setConstants($prefilledValues);
    // the third argument, which is null, is a "lable" which is legacy from the template design of QuickForm
    $form->addElement('text''username'null, array('class' => 'input'));
    // Vincent is going to probably want QuickFormRule to be an object, but this tells javascript to keep the length to 25
    $form->addRule('username''too damn long''maxlength'25'client');
    $formElements['username'] = array('label' => 'Username''field' => $form->renderElement('username'true));
    ob_start();
    include 
    'form.tpl.php';
    $formContent ob_get_contents();
    ob_end_clean();
    $form->addData($formContent);
    // You can use an include file here, I just am going to echo some wrapper tags
    echo '<html><body>';
    echo 
    $form->display();
    echo 
    '</body></html>';
    ?>

    <!-- form.tpl.php snippet -->
    <table class="formTable">
      <?php foreach ($formElements as $tmp_element) { ?>  
      <tr>
        <td class="formLabel"><?php echo $tmp_element['label']; ?></td>
        <td class="formField"><?php echo $tmp_element['field']; ?></td>
      </tr>
      <?php ?>
    </table>

    <!-- output -->
    <html>
      <body>
        <script language="javascript">
    <!--
            function validate_formName() {
                    var errFlag = new Array();
                    _qfMsg = '';
                    var frm = document.forms['formName'];
                    var field = frm.elements['username'];
                    var regex = /^(\s|\S){0,25}$/;
                    if (!regex.test(field.value) && !errFlag['username']) {
                            errFlag['username'] = true;
                            _qfMsg = unescape(_qfMsg + '\n - too%20damn%20long');
                    }               if (_qfMsg != '') {
                            _qfMsg = 'Invalid information entered.' + _qfMsg;
                            _qfMsg = _qfMsg + '\nPlease correct these fields.';
                            alert(_qfMsg);
                            return false;
                    }
                    return true;
     }
    //-->
        </script>
        <form action="index.php" method="POST" name="formName" target="_self" onsubmit="return validate_formName();">
          <table class="formTable">
            <tr>
              <td class="formLabel">Username</td>
              <td class="formField">
                <input class="input" name="username" type="text"/>
              </td>
            </tr>
          </table>
        </form>
      </body>
    </html>
    As you can see, it is necessary to come up with a way to inject your template into the QuickForm object or have your QuickForm object somehow take the result of your template. If you know what your form is going to look like, you could get a bit more specific with your template by using specific lables in specific places. I still see some issues with QuickForm, but that is at least a start.
    Last edited by mojavelinux; Jan 28, 2003 at 15:27.

  3. #3
    SitePoint Zealot Sork's Avatar
    Join Date
    Jul 2002
    Location
    Portugal
    Posts
    143
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    After reading this explaining of how PEAR's QuickForm works i realised the concept is similar to my eBFormGenerator that is almost finished.

    My set of classes, despite having similar methods and concepts, works more 'clean'. Without internal templates and without so many methods!

    If you guys want to have a look just say and i drop my code when is finished

  4. #4
    SitePoint Enthusiast
    Join Date
    Jan 2003
    Posts
    60
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thumbs up rock on!

    Alright! I had just came back to ask if anyone wanted to rewrite this class with me to make it clean, get rid of all the junk. Here are a few things about PEAR's quickform that annoys me that maybe we can look into fixing.

    1. It auto-assigns $_GET, $_POST values to form elements. I don't like this at all. I do like the idea of $form->setContants() which provides a set of name => value pairs to auto fill, which if necessary you could do something like $form->setContants($_POST)...but having it automatically pull in the global variables makes me pissed.

    2. Have functions for $form->start() and $form->end() which prints out the form tag, hidden elements and needed javascript for the start() and the end form tag for the end()...this would solve the problem with templates because instead of having to pass your template into the form, it allows you to place the parts of the form into our own template

    3. NO INDENTING...gosh what a WASTE of resources...QuickForm tries to indent to stay clean...but it never works, so what is the point! I can understand a few line breaks here and there were necessary, but forget the indenting, it is not needed. For that you should rely on an indenting engine which takes the output and pretties it up if it is sooooo necessary.

    4. Form element iterator...so that if you want to just go through all the elements in the form, you can just do reset(), isValid(), next() and getCurrent()...this is very key for working with any data object.

    I am sure there are several others, but we can talk about them as we go. Where is your class in relation to these inquires.

    By the way, please look up voostind if you have not yet and read his posts on OO programming, to make sure your class remains simple. What I don't want is another useless failed class...I believe the PHP world still lacks a good OO form class even though QuickForm came pretty close (too much bloat still).

  5. #5
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    How weird, I posted to this thread yesterday, but it looks like my contribution got lost in cyberspace somewhere... So here's another try.

    After reading this thread I opened the file QuickForm.php from PHP CVS into my browser. Just looking at the amount of code (not the contents) my opinion is simple: it is bloated.

    Looking a bit further, I see this class does a lot of very useful things. But everytime I see a sentence like "This system has the following features: [long list of cool and handy stuff]. The class can be download at [url]" I don't even look at it. So many features in a single class; that's NOT the right idea, IMHO.

    The class HTML_QuickForm allows forms to be created, rules and filters to be applied on the form elements, contents to be validated, and the entire form to be displayed. These properties are all very different, so why are they in a single class?

    The first time a form is generated, only a couple of the features in the class are used: the form is build, and the form is shown. The form hasn't been posted yet, so what is the point of having form validation and post-processing code in the system? It isn't used anyway. Conversely, if the form has been posted and processed correctly, it will probably not be displayed; instead some other action will occur. So why load the code necessary for displaying the form? If the class would have been split up in four or five (or maybe even more) small classes, this problem wouldn't even occur.

    I very much like the idea of applying filters and rules to user input. But, like already mentioned, I would like each filter and rule to be represented by separate classes. There would be two base classes, and these base classes might be related to each other too (what is so different between applying filters and applying rules?). Anyway, I like the idea of having filters, and I'm sure it could be useful for many other things. However, because all code necessary for filtering is present into this one big class, there is no possibility to use this code without using the other QuickForm code.

    To conclude: I admit I like what the class does, but I don't like its implementation, and I certainly don't think it's 'proper' OO. Proper OO is all about compact, powerful classes and using object composition to make them work together. And I don't see any of that here...

    Vincent

  6. #6
    SitePoint Enthusiast
    Join Date
    Jan 2003
    Posts
    60
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    excellent

    Excellent, I hardly expected a different reply as I sensed this class had long since reached the bloat level. But as I had pointed out already, it would be much better if this classed didn't try to do so much. What I do like about this class is that in the very least it does take a simple html tag and extends that class over an over to create the different types of input tags available, as well as letting you create your own. It seems to be that this is polymorphism as it was intended. (Please note that I agree it is one of the few good things it does and that I am getting away from PEAR this minute to start on a new path).

    However, it would seem like QuickFormRule should be a seperate class (just as you point out) and can be extended for the different types of rules available and then you can pass the rule into the element when it is created (or rendered) so that it can make use of the rule (assuming it is javascript or whatever). This technique is the one called composition (I believe).

    Now that you have set the record straight on QuickForm for me, I don't see how I could ever wrongly accept a library as proper OO which is really just procedural bloat again. What I find myself getting better at with each post I read leading up to your response is anticipating what you might say. While I will be the first to admit that I am not a "formally" trained programmer (only a BS), I have faith that if I study and practice the techniques which you have presented by not only studying the numerous books you have mentioned, but by working with others to understand how case studies fit into this model, I will be able to think along the same lines as a "real" programmer like yourself. You have truly given people in this forum hope that they can, with enough effort, break away from the pool of PHP programmers out there and make something better.

    You are so right about PEAR it almost makes me feel like my heart is now missing, but that is good, because I will replace it with something better. Just tonight I was attempting to use the Auth class and realized something you said earlier to be very applicable. There is no one class that will satisfy everyone's needs and the more you add, the more it becomes crap. If instead you worked on a layered approach, then PEAR would have many, many, many more classes, but they would be classes which could be extended or morphed into something the programmer can use without rewriting much or inheriting useless methods. But you are correct, PEAR was made big and nasty so that the average scripter could just get as much pre-written functionality as possible, without having to consider his/her own design. (It is almost shameful to see O'Reilly's new PHP Programming book delve into PEAR...I guess you throw enough at something and eventually it will gain some sort of backing, justifiable or not...take windows)

    So one has to ask, dying to ask. PEARII? A fork to start all over with something better? Not that you have nothing to do, but there is no doubt you have been beat over the head with a genius stick and if PHP is going to be taken seriously, like the java community, maybe we need this...Maybe you don't have to do any work, you can just be the GodFather. You have taugh enough people around here already. We don't need to make every class tomorrow, but Eclipse could be the right start. I know you want it to be yours, and perhaps you can still use just your class, but your expertise could at least cycle a development of Eclipse's brother.

    Sorry to go on so much...if you are interested in gathering some of the very intelligent people that obviously frequent this forum and produce something like eclipse.php.net, perhaps we can start a new thread for that. If you are not interested, would you at least consider being an advisor? Again, let's start a new thread for that and keep this one to quickform.
    Last edited by mojavelinux; Jan 29, 2003 at 04:39.

  7. #7
    SitePoint Zealot Sork's Avatar
    Join Date
    Jul 2002
    Location
    Portugal
    Posts
    143
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    By the way, please look up voostind if you have not yet and read his posts on OO programming, to make sure your class remains simple. What I don't want is another useless failed class...I believe the PHP world still lacks a good OO form class even though QuickForm came pretty close (too much bloat still).
    I presume you're refering to me.
    For a while i'm using voostind's lib on my projects, and i have to say that being not an expertise on programming after look to eclipse lib i understood what they do and how they work - Thanks Vicent

    In my eBFormGenerator i separated each element in classes for example:
    TextElement extends eBFormInputElements
    and
    eBFormInputElements extends eBFormElements

    I guess this is how PEAR's QuickForm works - just have a quick look on it.
    But no templates or other stuff, just what we need to generate forms is what i want my eBForm to do.
    Sorry to go on so much...if you are interested in gathering some of the very intelligent people that obviously frequent this forum and produce something like eclipse.php.net, perhaps we can start a new thread for that. If you are not interested, would you at least consider being an advisor? Again, let's start a new thread for that and keep this one to quickform.
    That was very good thing to php development

    And mojavelinux if you want to help me on my form classes it would be very apreciated, i like to have a second opinion and i certainly we would learn more

  8. #8
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PEAR is an interesting subject. For me I think they've let themselves be inspired too much by Perl's CPAN and the concept of a Perl Module (note that's a generalization - many Perl modules such as this simply add a discrete set of functionality wrapped in a class. Others are more complicated and seem to take advantage of inheritance / encapsulation etc. such as DBI.). In PHP the "tradition" has been to provide this type of discrete functionality within an extension. Typically a PHP library offering a limited subset of functionality will act as a fore runner to the development of a PHP extension (as has been the case with XML-RPC, DOM-XML and should soon be the case with SOAP)

    Think it would be better if they considered something approaching a class library like Java's but bearing in mind the fact that much of Java's library is effectively implemented in core PHP functions or extensions.

    PHP is generally used to tackle different kinds of problems to Perl. Developing web applications exposes you to (almost - minus stuff like complex event handling and threading) the full range of issues that face desktop GUI developers.

    For PEAR to offer real value I think it has to deliver framework solutions to some degree, and have in mind some kind of overall plan for where it's going.

    One prime example of the problem (or perhaps the symptom), relevant to this discussion is another package in PEAR I just saw Pager_Sliding, which provides a Google like paged result set (it seems). From the change log;

    2003-01-28: Added a select box builder
    Now wait a second! Select box? Shouldn't that be part of QuickForm?

    First there needs to be the realisation that there's a problem. From the Andrei Interview;

    SP: [...] Do you feel the Pear library is ready to deliver a standard application framework for PHP? Is there an alternative project you feel should be endorsed by the PHP group?

    AZ: First of all, PHP group is not in the business of endorsing projects or products.

    Secondly, PEAR has made great strides in the last few months and with the 4.3.0 release of PHP it will finally be possible to transparently download and install whatever libraries you wish. But PEAR is not an application framework, rather it is a collection of components, some of them serving the same purpose, that can help you rapidly develop your applications.
    I think that's a mistake. PHP-GTK (developed by Andrei) by contrast is an application framework.

    The obvious argument against that is PEAR shouldn't be about offering a single framework for developing apps, with which I'd have to agree, but if we look around the web today, there's only a few approaches to frameworks which have proved themselves. Some, off the top of my head, would be Fusebox, Cocoon (in PHP: Krysalis) and Struts (basically MVC - in PHP: Phrame or Ambivalence).

    Bearing those in mind PEAR could offer a choice of framework (the Apache group successfully offer a number of alternative web frameworks). Contributed classes can then be required to comply with one of more of the available frameworks. Vincent's Eclipse, for example, could pretty much comply with all as it's focused almost entirely on data related operations. All sorts of other classes could then benefit from Vincents Iterator classes, for example.

    PEAR has gained acceptance (as OReilly demonstrate) as potential place for PHP development standards to stem from but as yet fails to deliver, IMO.

    This is a shame because without a standard development approaches, the wealth of PHP projects out there will never be re-usable or "integratable". If PEAR offered a standard library for web site security, for example, phpBB might use it then we'd finally be able to integrate it with other applications on our site.

    Until then projects like eZ publish will be forced to create their own class libraries. Right now I think phpClasses still offers better value than PEAR...

  9. #9
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree that this QuickForm class, and the same goes for any PEAR class, tries to do too many things at once. At first this may seem like it can be reused in many projects, but in the long term it will actually turn out to be unusable. Because it tries to do so much by itself, you can not combine it with other classes.

    One obvious disadvantage I can think of, in fact I experienced it myself, is this: by combining the presentation and validation of forms, you can not validate forms coming from a stand alone HTML file. In the class library I developed for personal use, I had to set up all form elements combined with validation rules before I could validate the form. I could not use this to validate form submissions coming from a template file I did not build with the form classes, so I had to do validation the 'old-fashioned way'.

    PHP-GTK (developed by Andrei) by contrast is an application framework.
    Harry, I know you have the Design Patterns book, so you might want to read up on the definition of framework again. The difference between a class library, like Eclipse and PEAR are (although the latter is questionable..), and a framework, is that you call the class library's code, while a framework calls your code. I don't think that PHP-GTK's event handling counts as 'the framework calling your code'.

    I think [PEAR's] let themselves be inspired too much by Perl's CPAN and the concept of a Perl Module
    When you ask Perl coders "what's so good about Perl", they'll most likely answer "CPAN" (so I've read, not that I have actually asked one myself ). I think an important reason for PEAR's existance is to create a sort of CPAN for PHP so PHP could compete with Perl on that area.

  10. #10
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You're right I wasn't being too careful about the use of the word framework but looking at the PHP GTK Hello World example the PHP-GTK connect() method allows you to specify your own callback function to run on an event.

    When you ask Perl coders "what's so good about Perl", they'll most likely answer "CPAN" (so I've read, not that I have actually asked one myself ).
    Note I'm not knocking CPAN at all but saying most of the equivalent functionality in PHP ends up in the base install or an extension.

    Sure for those people that have their server run for them by someone else, having a PHP library as a slower alternative to an extension is probably nice but here's where I think sites like PHPClasses do a better job (offering more choice). In other words by focusing on "one off" solutions to problems, PEAR doesn't have much scope to provide useful code.

    Back to QuickForm, shouldn't the validation functionality be part of a seperate class (which other classes could use?). Also glancing at the date "element" offered, think there's more which could be elsewhere.

    What I dont see is how they can take any real advantage of encapsulation, without some kind of overall plan for where they're going?

    Having mentioned CPAN and talked with the "guy opposite" it seems it is fairly well planned in that modules depend on / re-use others (suggesting encapsulation). So may be CPAN is a good target to head for after all.

  11. #11
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Having mentioned CPAN and talked with the "guy opposite" it seems it is fairly well planned in that modules depend on / re-use others (suggesting encapsulation).
    Isn't that against one of the goals of OOP, removing the dependencies of one piece of code on another one? Just a thought

  12. #12
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Isn't that against one of the goals of OOP, removing the dependencies of one piece of code on another one?
    Yeah OK but it's not as simple as that. What's one sure fire way to remove the dependence of class A code on class B? Merge them... which is not what we want.

    Loose coupling yes but complete independence no. If we have an class for parsing remote RSS feeds over HTTP, it's preferable that it doesn't implement HTTP functionality internally but rather uses another class to do that for it. There's a whole ton of stuff you could build into an HTTP client (e.g. how to deal with proxy servers that expect you to authenticate). All this is clearly nothing to do with RSS feeds.

    It think it's reasonable to have "default" dependencies i.e. other classes that a class was intended for use with. There should be ways round them though, by using Adapters and so on, so you could replace one required class with another.

  13. #13
    SitePoint Member
    Join Date
    Oct 2002
    Location
    Paris, France
    Posts
    18
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is a bit off-topic, but this thread has more or less moved to a discussion about PEAR.

    I see PEAR as a more or less heterogeneous collection of PHP classes, provided to help the wider range of developers getting started fast with several functionalities. Note that if only one package is used, then PEAR may not be the best choice because of the 30kb common PEAR.php code usually required_once().

    It is certainly not a framework, and the key word here is "heterogeneous": I don't see much consistency between packages, I see no guidelines or standards (except those coding standards), and no project manager whose role is to make sure everything is homogeneous, elegant as well as performant.

    Instead, scripts are contributed by different people who probably don't talk too much to each other. You finally end up with a lot of different classes, some of them providing their own solution to already solved problems in other classes.

    Does that make PEAR suck? I don't think so. Even if some classes suck, some people probably find PEAR useful to them. Those people don't care about how it is written, as long as it works the way it is publicized. Now, should the PHP Group endorse several frameworks, the same way the ASF did? Definitely yes, especially with all this buzz about PHP 5 (being "enterprise ready"). One of them could be written by a group made of some of those talented people here

    Now, regarding the original subject, I found this page <URL:http://developer.java.sun.com/develo...amming/struts/> earlier when I was looking for some information about Struts. It includes a chapter from the book "Struts in action" about how it deals with validating user input. You will find it interesting to read, although I thought Struts solution was not simple enough ("KISS"). I already mentioned Struts here: a good thing about this framework is that there's a lot of information available about it, and it's always interesting reading how developers solved those common web "problems".

    You will also find this article, Making PHP forms object-oriented (<URL:http://www.devarticles.com/art/1/388/>) an interesting reading.

  14. #14
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by HarryF
    Vincent's Eclipse, for example, could pretty much comply with all as it's focused almost entirely on data related operations. All sorts of other classes could then benefit from Vincents Iterator classes, for example.
    Originally posted by voostind
    After reading this thread I opened the file QuickForm.php from PHP CVS into my browser. Just looking at the amount of code (not the contents) my opinion is simple: it is bloated.
    Ironic. When I first downloaded eclipse, I saw that it had an iterator class and thought "it is bloated."

    Lets look at the iterator class from interator.php. This is a standard pure abstract class. This would be well and good in a statically typed compiled language like C++, but makes little sense in a language like PHP.

    In some languages like delphi or java, one might formalize Iterator into a interface declaration. In a dynamic language like PHP, this is unnecessary. You can send a "next" message to any class, regardless of type.

    For example, go to any of the subclasses of Iterator and remove the "extends iterator" and the require_once for iterator.php. Now delete iterator.php. Everything still works the same.

    This changes the concept of "Interator" from a class to a pattern. (Small P pattern like the java get and set methods) Simply make a convention that any class that ends in the word "Iterator" will support the Rest, IsValid, getCurrent, and next methods.

    Why not keep the base class? Because PHP code is usually interpreted. More code is slower. Here is a sample code from the StringIterator class documentation:

    PHP Code:
    <?php
    require "StringIterator.php";

    $string 'Encrypt me!';
    $key    = array(-13, -2001);
    $size   count($key);
    $index  0;
    for (
    $it =& new StringIterator($string); $it->isValid(); $it->next()) 
        {
        
    $char  =& $it->getCurrent();
        
    $char  =  chr(ord($char) + $key[$index]);
        
    $index =  ($index 1) % $size;
    }
    print 
    'Encrypted string: ' $string;
    ?>
    Benchmarking this with ab Yields a mean time per request of 19.03 ms
    After removing the base class: 15.07 ms

    so on my machine it takes about 4 ms to parse iterator.php each request.

    benchmark was done using ab -n 1000.

    BTW, You should always benchmark using ab when you have differing code sizes in PHP because it takes into account the file parsing time. Very often in PHP simple small algorithms that parse quick and run slow (tortoise) will beat out more complex algorithms that run quicker (the hare).

    I picked string iterator for a reason. I have no idea what one would use it for. I do not see what value it has except as an example of how to make an iterator.

    Here is the same code using built in PHP functions:

    PHP Code:
    <?php
    $string 
    'Encrypt me!';
    $key    = array(-13, -2001);
    $size   count($key);
    $index  0;
    for (
    $i 0; ($i strlen($string)); $i++) 
    {
        
    $string{$i}  =  chr(ord(($string{$i})) + $key[$index]);
        
    $index =  ($index 1) % $size;
    }
    print 
    'Encrypted string: ' $string;
    ?>
    The native version benchmarks at 9.38 ms mean time per request.
    So not only is this code smaller, but it is faster.

    For comparison purposes:

    PHP Code:
    <?php
    echo "Encrypted string: Dqaryqs#ke!";
    ?>
    Benchmarks at 7.99 ms per request. This demonstrates the basic overhead of making a http request to a php page. The native version seems to actually take only 1.39 ms to execute per request more than the basic overhead, while the first String Iterator version takes 11.04 ms to execute per request more than the basic overhead. Remember the tortoise and the hare.

    Iterators are useful in the right circumstances, but I feel they are overkill for most cases in PHP.

    I do like the database classes in eclipse. They are deliciously spartan. They could use some performance tuning, though.

    Two more benchmarks:

    PHP Code:
    include "MyDatabase.php";
    include 
    "QueryIterator.php";
    $db =& new MyDatabase('test''localhost');
    $db->connect('test''test');

    $query = new QueryIterator($db->query("SELECT * FROM test"), ECLIPSE_DB_ASSOC);
    for (
    $query->reset(); $query->isValid(); $query->next()) {
        
    $Record =& $query->getCurrent();
        echo 
    "Record: " $Record['test'] . '<br>';

    runs in 39.54 ms for 26 records.

    PHP Code:
    $db mysql_connect('localhost''test''test');
    mysql_select_db('test'$db);

    $query mysql_query("SELECT * FROM test"$db);
    while (
    is_array($Record mysql_fetch_array($queryMYSQL_ASSOC))) {
        echo 
    "Record: " $Record['test'] . '<br>';

    Runs in 14.27 ms per request over 26 records.

    I played around with the eclipse code for about 10 minutes and was able to get the execution time down to 22.40 ms without changing the essential interfaces by putting a MyQueryIterator into mydatabase.php, folding the database.php functionality into mydatabase.php, and eliminating some methods of questionable utility by applying the YAGNI principle.

    This surprised me a bit because the DB class that I normally use took 25.51 ms.

    Originally posted by mojavelinux
    4. Form element iterator...so that if you want to just go through all the elements in the form, you can just do reset(), isValid(), next() and getCurrent()...this is very key for working with any data object.
    I fail to see what value an iterator would provide. I am not sure you would want to iterate over the elements (YAGNI), but if you were, why not just return a reference to an array and use the standard PHP functions for this task? The phrase "We might need that" is what lead to the PEAR bloat in the first place.

  15. #15
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For example, go to any of the subclasses of Iterator and remove the "extends iterator" and the require_once for iterator.php. Now delete iterator.php. Everything still works the same.
    Correct. But if I'm not mistaking, this is also mentioned in the documentation of the library.

    Saying that abstract base classes make no sense in dynamic languages is a bit crude; it depends on your point of view. Clearly, yours is different than mine. For example, class Loop implements an algorithm on an 'Iterator'. By putting a base iterator in the code, it immediately becomes clear what it is and what it should look like. You don't need to read the documentation for any other iterator class. But then I admit I have a purist kind of view.

    Very often in PHP simple small algorithms that parse quick and run slow (tortoise) will beat out more complex algorithms that run quicker (the hare).
    With 'parse quicker' I assume you mean 'less code'? Here it is clear how our views differ. I would never, ever select the slow algorithm over the quicker one for these reasons.

    All comments you made are valid, but they all apply to constant overhead costs: reading PHP files from disk and parsing them. On a single page, any class in the library will be loaded at most once, so this is a constant overhead. It's pretty easy to get this overhead down:
    - Buy decent hardware
    - Put the library in shared memory instead of on disk.

    Again, my point of view is that the design and implementation of a program should never suffer just to tweak performance. A good design already leads to compact and fast code. IMHO, further gains in efficiency should not be achieved by tweaking the software, but by optimizing the hardware.

    I fail to see what value an iterator would provide
    The largest part of activity in code is processing lists. These lists may be arrays, but they can also be query results or lines in files. If you use iterators you can write code in such a way that the algorithm doesn't care what kind of list it's processing. The datatype is abstracted through a simple design pattern (the Iterator). This is about the best I can do in explaining it, so if you still don't understand, then I would kindly ask you to read up on iterators elsewhere, for example in the Design Patterns book, the Java library (or the Bruce Eckel 'Thinking In Java' book) and the Ruby book.

    Vincent

  16. #16
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    Correct. But if I'm not mistaking, this is also mentioned in the documentation of the library.

    Saying that abstract base classes make no sense in dynamic languages is a bit crude; it depends on your point of view. Clearly, yours is different than mine. For example, class Loop implements an algorithm on an 'Iterator'. By putting a base iterator in the code, it immediately becomes clear what it is and what it should look like. You don't need to read the documentation for any other iterator class. But then I admit I have a purist kind of view.
    The base class does serve as a nice place to accumulate documentation. I would be inclined not to actually include it though, and change the "extends iterator" to "/* implements iterator */"

    With 'parse quicker' I assume you mean 'less code'? Here it is clear how our views differ. I would never, ever select the slow algorithm over the quicker one for these reasons.
    Given a choice between a 10 line algorithm that is simple and slow versus a 100 line algorithm that is complex and fast, I will choose simple every time. Often in PHP the time to parse the extra lines of code does not make up for the difference in speed between algorithms. I see people get on the wrong side of this tradeoff. I wouldn't choose the complex algorithm unless the application appears slow. More code = more bugs.

    All comments you made are valid, but they all apply to constant overhead costs: reading PHP files from disk and parsing them. On a single page, any class in the library will be loaded at most once, so this is a constant overhead.
    Agreed. The parsing time is constant. Also, the more complex the page you are generating, the more you can afford the parsing time.

    Again, my point of view is that the design and implementation of a program should never suffer just to tweak performance. A good design already leads to compact and fast code. IMHO, further gains in efficiency should not be achieved by tweaking the software, but by optimizing the hardware.
    Agreed. Premature optimization is the root of much evil.

    The largest part of activity in code is processing lists. These lists may be arrays, but they can also be query results or lines in files. If you use iterators you can write code in such a way that the algorithm doesn't care what kind of list it's processing. The datatype is abstracted through a simple design pattern (the Iterator). This is about the best I can do in explaining it, so if you still don't understand, then I would kindly ask you to read up on iterators elsewhere, for example in the Design Patterns book, the Java library (or the Bruce Eckel 'Thinking In Java' book) and the Ruby book.
    I know what iterators are. I just meant that I didn't see that they would add value in the specific case mentioned in PEAR Quickform. Just as I don't see how they add value in the string encryption example in my last post.

    I've attached an alternate implemention for QueryIterator, MyDatabase, and MyQueryResult. I've combined them into a single class which is about 90 lines of code.

    It implements the eclipse interator interface and I think it can be used anywhere in eclipse that an iterator can be.

    There are a few functions that it does not implement, but I doubt those were ever called anyway.

    It has the same functionality, except I did not include the transaction constructor. It also only returns assoc arrays and does not give you a persistant connection choice.

    It has a very different way of connecting to the database.

    It is about twice as fast as the eclipse implementation.
    Attached Files Attached Files

  17. #17
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The base class does serve as a nice place to accumulate documentation. I would be inclined not to actually include it though, and change the "extends iterator" to "/* implements iterator */"
    That's an option too, indeed. Still I consider it 'better' (as in: looking nicer from a purist kind of view) to write the base class. A matter of opinion, I guess.

    Given a choice between a 10 line algorithm that is simple and slow versus a 100 line algorithm that is complex and fast, I will choose simple every time
    Let's drop this particular subject, because I think we agree on the essence of what we're talking about, but not on the terminology used. For example your line '100 line algorithm that is complex is fast' is something I can never see happen. IMHO a complex algorithm is never fast, and a fast one never complex. Anyway, I think we agree

    I just meant that I didn't see that they would add value in the specific case mentioned in PEAR Quickform. Just as I don't see how they add value in the string encryption example in my last post.
    The StringIterator is merely present to give a more or less complete set of Iterators: there's one for built-in arrays, there's one for built-in numbers, so why not supply one for strings? Like you I have no idea what anyone would want to do with it. But then, I can't presume there's no use for it either... (I know remember I used it myself once, so there you go!)

    In the PEAR Quickform there could be many uses for iterators. For example, a form is typically constructed by adding a set of fields to it, each field having a number of properties. For example (I picked this line from a random piece of code in this thread):

    PHP Code:
    $form->addElement('text''username'null, array('class' => 'input'));
    // More lines like this one, adding fields to the form 
    This technique allows forms to be constructed programmatically. But what if I wanted to do it dynamically, by specifying a form configuration in a text file or in a database? Now imagine class Form had a method 'buildForm' like this:

    PHP Code:
    function buildForm(&$it) {
        for (
    $it->reset(); $it->isValid(); $it->next()) {
            
    $settings =& $it->getCurrent();
            
    $this->addElement($settings['type'], $settings['name']);
        }

    This (simplified) algorithm uses an iterator to put the elements on the form. Why not a simple array? Well, the source of the configuration need not be an array. For example:

    PHP Code:
    $form =& new Form('test');
    $form->buildForm(
        new 
    QueryIterator(
            
    $db->query('select * from fields where id = \'test\'')
        )
    ); 
    This would initialize the form from a query result. But it could easily be changed to accept an array or a text file. The point is: the implementation of class Form doesn't force you to pick some predefined datastructure. You can pick whatever you want.

    Similar techniques using iterators could be applied to the filters and validation rules. Or, you could use an iterator simply because it's so easy. Remember that using 'foreach' on an array is typically not a good idea, instead you have to use the built-in array methods. You might not like that (I certainly don't).

    I've attached an alternate implemention for QueryIterator, MyDatabase, and MyQueryResult. I've combined them into a single class which is about 90 lines of code.
    I believe your code is indeed much faster. But then, you could never put it in a library of some sort, because it assumes too much. For example, you assume the user always uses a single database connection. You 'globalize' this database connection so a user never has to access it directly. But what if I wanted to use two or more separate database connections? Then I'd have to hack your script. Your script uses MySQL. What if I wanted to use PostgreSQL? I could copy your code and replace the mysql_-functions with psql_-functions, true, but that's not good enough. What if I wanted to use both a MySQL and a PostgreSQL database connection at the same time? Because your function 'ConnectToDatabase' is global, there can be only 1 definition of it, either a MySQL one or a PostgreSQL one. So again I'd have to hack the script. There's nothing wrong with this if you're writing the code for yourself, but if you want others to be able to use it without examing the code (only looking at the interface), this is clearly not the way to go. When you're writing a library you can assume nothing.

    Another thing you did is tightly couple the query result with the iteration. Most of the time there would be no problem, but using a separate iterator it is possible to do this:

    PHP Code:
    $result $db->query('select * from table');
    $it1 =& new QueryIterator($result);
    $it1->next(); // 2nd row
    $it2 =& new QueryIterator($result);
    $it1->next(); // 3rd row
    $it2->next(); // 2nd row
    $it2->reset(); // 1st row
    $it1->next(); // 4th row 
    In other words, you can build multiple completely separate iterations on the same query result at the same time. Naturally, this is almost never an issue. But again, as a library implementor you cannot assume it never is.

    All in all: nice try, but no dice

    There are a few functions that it does not implement, but I doubt those were ever called anyway.
    Could you name those please? I use my own library a lot, and as far as I recall there is no single method I do not use. So I'd be very interested to know which method you think are unnecessary.

    Vincent

  18. #18
    SitePoint Addict
    Join Date
    Aug 2002
    Location
    Ottawa, Ontario, Canada
    Posts
    214
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Benchmarking this with ab Yields a mean time per request of 19.03 ms
    After removing the base class: 15.07 ms

    so on my machine it takes about 4 ms to parse iterator.php each request.

    benchmark was done using ab -n 1000.
    Can anyone provide insight on this benchmark (link)?

    A Google search using "AB PHP benchmark" got me a bunch of MySQL AB hits

    I would like to use a benchmark other than time2-time1 at the bottom of a page

    Cheers,
    Keith.

  19. #19
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    Let's drop this particular subject, because I think we agree on the essence of what we're talking about, but not on the terminology used. For example your line '100 line algorithm that is complex is fast' is something I can never see happen. IMHO a complex algorithm is never fast, and a fast one never complex. Anyway, I think we agree
    We do agree. However, I have seen an example of people using complex algorithms where simpler ones would do because they thought the complex one was faster without correctly measuring the real difference.

    Is a QuickSort faster than a bubble sort? Which implementation is bigger? Which is simpler?

    The StringIterator is merely present to give a more or less complete set of Iterators:
    I suspected as much. So where is your directory iterator for the file system.


    Ok, I can see what you mean in PHP QuickForm. My hunch is that iterators would be overkill for most things there, but I will conceede that they might have a use somewhere. I suspect in conjuction with creating a form that allowed you to edit several records in a database at the same time.


    I believe your code is indeed much faster. But then, you could never put it in a library of some sort, because it assumes too much.
    Sure you could. There is nothing wrong with making assumptions as long as they are good ones.

    For example, you assume the user always uses a single database connection. ... So again I'd have to hack the script.
    Yes, I did. It was not intended to be a multiple database solution. it was only meant to be an example of an alternate iterator implementation, not a general purpose library.

    When you're writing a library you can assume nothing.
    But you do make assumptions anyway. For example, you assume that I might want to access two different databases at the same time.

    Another thing you did is tightly couple the query result with the iteration. Most of the time there would be no problem, but using a separate iterator it is possible to do this:
    True. However, With the multiple iterator example, the iterators are not really independent anyway because they share the same query resource. I simply cannot imagine the ability you describe ever being useful.

    Could you name those please? I use my own library a lot, and as far as I recall there is no single method I do not use. So I'd be very interested to know which method you think are unnecessary.
    Some of the smaller accessor methods. I chose to trigger_error on a bad query instead of having get_error and IsSuccussful (?) I left out GetRow, although you might be able to make a case for it.

    I think some of these may only be used from within the library itself and some may only be there for the sake of completeness. (like the StringIterator)

  20. #20
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ab - Apache HTTP server benchmarking tool
    http://httpd.apache.org/docs/programs/ab.html

  21. #21
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I suspected as much. So where is your directory iterator for the file system.
    It's right here in my Eclipse 3.2 development edition...

    But you do make assumptions anyway. For example, you assume that I might want to access two different databases at the same time.
    Considering the smiley I know you made a joke, but this is a serious remark you shouldn't simply 'brush aside'. Eclipse was meant as a general purpose library, and as such its implementation cannot make too many assumptions. Eclipse, as it is now, allows as many database connections as you want, on various database systems, all at the same time. Iterators are decoupled from the data structures they work on so you can have as many as you want. As such Eclipse offers you great flexibility. It has to, because it's a general purpose library. It works for simple things, but also the most complex things you can think of. That's general purpose.

    Your example code could be in a library, but that would be a personal one, meant for specific purposes (supporting web sites developed by yourself). That's an important difference.

    I simply cannot imagine the ability you describe ever being useful.
    Ah! So because you can't think of anything useful, it's probably not going to be useful to anybody? That's a bit narrowminded, isn't it? (You might even call it arrogant: "If I can't think of something, surely nobody else ever will...")

    I'm not saying I have a specific example in mind of where this ability might prove useful. But consider this:
    1. It is possible now.
    2. It costs little.
    So why remove the ability from the library, gaining nothing and disabling some of its possible uses, in fact even crippling it?

    I think some of these may only be used from within the library itself and some may only be there for the sake of completeness. (like the StringIterator)
    They aren't. The getRow is necessary because there is no other way to access the rows in a query result. Note that you don't have to use the iterator if you don't want to. You can easily write:

    PHP Code:
    $result =& $db->query('select * from table');
    for (
    $i 0$j $result->getRowCount(); $i $j$i++) {
        
    $row =& $result->getRow($i);
        
    // do something useful with $row

    This is perfectly fine. However if you want additional flexibility (through abstraction) then you can use an iterator instead.

    The getErrorMessage() and isSuccess() methods are there for a reason too. The first allows you to report a message as generated by the database to the client. The second allows you to implement specific behavior when something goes wrong. For example:

    PHP Code:
    $db =& new PgDatabase('test''test');
    if (!
    $db->connect('user''pass')) {
        
    // Host not found? Illegal username and/or password? 
        
    echo $db->getErrorMessage();
        exit();
    }

    $result $db->query('insert into table (field1) values (1)');
    if (!
    $result->isSuccess()) {
        
    // syntax error in SQL? Integrity constraint?
        
    echo $result->getErrorMessage();  
        exit();

    So are you sure there are methods that are not useful?

    Vincent

  22. #22
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    Considering the smiley I know you made a joke, but this is a serious remark you shouldn't simply 'brush aside'. Eclipse was meant as a general purpose library, and as such its implementation cannot make too many assumptions. Eclipse, as it is now, allows as many database connections as you want, on various database systems, all at the same time. Iterators are decoupled from the data structures they work on so you can have as many as you want. As such Eclipse offers you great flexibility. It has to, because it's a general purpose library. It works for simple things, but also the most complex things you can think of. That's general purpose.

    Your example code could be in a library, but that would be a personal one, meant for specific purposes (supporting web sites developed by yourself). That's an important difference.
    Again, it wasn't meant to be in a library. Its actually a stripped down version of code that I actually do use, which was modified to support your iterator interface. It was designed to be a minimal baseline to demonstrate how a better performing iterator could be implemented and still conform to your interface.

    It could just as easily implement your style of connections as mine. This would not really change its performance characteristics, although it would change the way that you call it.

    Just because a library only supports one database at a time, doesn't make it not a Library (note the capital L). Its merely a different set of assumptions. For example, you state on your web site that your library does not implement many database features. You assume that your library should not attempt to homogenize disparate databases, unlike PEAR. I happen to like this assumption.

    Assuming that you will only support one database at a time is not wrong. just different.

    I am not suggesting that you give up your support for multiple database. I AM suggesting that you could implement the exact same functionality a little bit differently and get significantly better performance without sacrificing any generality.

    Performance is a legitimate characteristic for evaluating a general purpose library.


    Ah! So because you can't think of anything useful, it's probably not going to be useful to anybody? That's a bit narrowminded, isn't it? (You might even call it arrogant: "If I can't think of something, surely nobody else ever will...")

    I'm not saying I have a specific example in mind of where this ability might prove useful. But consider this:
    1. It is possible now.
    2. It costs little.
    So why remove the ability from the library, gaining nothing and disabling some of its possible uses, in fact even crippling it?
    The Possible/CostsLittle argument is what leads to code bloat. There is always a cost and just because can doesn't mean that you should. These things add up.


    Circa 1996, I was asked to analyze the development processes of two different development teams.

    Team A's project had a half a million lines of code, 500 tables, and over a dozen programmers. Team B's project was roughly 1/6 the size.

    Over the course of several months, management noticed that team A was roughly twice as productive as team B. One would think that the smaller team would be more productive.

    I spent several months analyzing the code from both projects, working on both projects and interviewing programmers. Finally I did an exercise which lead to an epiphany. I counted each line of code in both applications and assigned them to one of a half a dozen categories: Business logic, glue code, user interface code, database code, etc.

    If one considers that in these categories, only the business logic code had any real value to the company. It turned out that Team A was spending more time writing the code that added value, while team B was spending more time gluing things together.

    In the 70s an AI researcher named Doug Lenat (?) wrote a program called AM that could discover mathematical proofs. One of the arguments against this actually being an example of computer creativity is that AM used a very rich notational language in his problem domain (mathematics). Even generating random symbols in this notation made it hard not to come up with a proof of some kind.

    Team A had a set of libraries which was suited to the task which they were performing. Team B had a set of Much more powerful and much more general purpose libraries.

    So, Team A was more productive because the vocabulary that their tools provided spoke "Their problem domain," while team B was always translating. In addition, team A had uses several patterns and conventions for doing common tasks, while Team B left things up to the individual programmers, so there was much more variation. (especially because their powerful library had so many different ways to everything.)

    This is why I prefer PHP for web development. PHP is crappy language. however, I feel it "speaks" web development better than more general purpose languages do, so I put up with some of its idiosyncrasies.

    There would be no shame (in fact I recommend it) to make the assumption with eclipse that your developers will be developing web applications. That the most common type of iterator to use will be a database one. That they will read from the database more than write to it.

    One thing I learned from this exercise is that when designing a library you should make the common case easy. Your libraries and tools should form a vocabulary in your problem domain.

    One thing that I look at when designing a library is how simple is the common case. This is where I don't care for eclipses iterator interface.

    So I look at this common case:
    PHP Code:
    include "MyDatabase.php";
    include 
    "QueryIterator.php";
    $db =& new MyDatabase('test''localhost');
    $db->connect('test''test');

    $query = new QueryIterator($db->query("SELECT * FROM test"), ECLIPSE_DB_ASSOC);
    for (
    $query->reset(); $query->isValid(); $query->next()) {
        
    $Record =& $query->getRow();
        echo 
    "Record: " $Record['test'] . '<br>';

    And I ask. How could this case be made simpler. Here is a simpler version:
    PHP Code:
    include "MyDatabase.php";
    $db =& new MyDatabase('test''localhost');
    $db->connect('test''test');

    $query $db->query("SELECT * FROM test");
    while (
    $query->next()) {
        
    $Record =& $query->getRow();
        echo 
    "Record: " $Record['test'] . '<br>';

    NO capability is lost. The simpler version would have a different simpler iterator interface:

    reset()
    next()
    getRow()

    Having worked on this an example of the most common simple case, I would then go develop the library that would make this happen.

    I am not suggesting that you change your iterator interface. I am just trying to show why I thought it was bloated when I originally evaluated it.

    There is nothing wrong with eclipse. it is well written and elegant from a certain perspective. Its just not what I would like.

    They aren't. The getRow is necessary because there is no other way to access the rows in a query result. Note that you don't have to use the iterator if you don't want to. You can easily write:
    Ah, your getRow performs three functions: It seeks to a specific record index, it fetches a record and advances the true record pointer, and it returns the record in one of three formats.

    The seek is unnecessary except in your iterator implementation. In a typical web application, it is not really necessary to move around in the db cursor randomly. Top to bottom usually suffices. in fact it is really only here because your iterator class works on an "indexed" or "array" conceptual model, rather than on a "sequential access" or "database cursor" conceptual model. This is one of the things I don't like about the eclipse iterator implementation. The interface does not provide for an indexed access mode, yet internally it uses an index model versus a sequential model. The consequences are illustrated by code snippets above.

    I would also ditch the ASSOC, NUM, and BOTH choices. go with either ASSOC or BOTH. I would go with ASSOC, but your default of BOTH is fine. The ability to choose is unnecessary. ASSOC would be good for 99% of the cases. for the other 1%, you can provide a converter function which resides in a separate file, outside of the commonly included files.

    Do you see how getRow in QueryResult is really just getCurrent in the Iterator class.

    If your iterator was DB aware, then getRow would be unnecessary. Do you ever call getRow, from outside the eclipse library itself?

    PHP Code:
    $result =& $db->query('select * from table');
    for (
    $i 0$j $result->getRowCount(); $i $j$i++) {
        
    $row =& $result->getRow($i);
        
    // do something useful with $row

    Your iterator class provides this capability and you should be using it. not getRow.

  23. #23
    SitePoint Evangelist
    Join Date
    Oct 2001
    Posts
    592
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Again, it wasn't meant to be in a library. Its actually a stripped down version of code that I actually do use, which was modified to support your iterator interface. It was designed to be a minimal baseline to demonstrate how a better performing iterator could be implemented and still conform to your interface.
    What's the point of doing that? Given any library I can easily write code that's much faster but still conforms to the interfaces in that library. But there's no real use in doing that. You can easily compare your "faster, not meant for a library"-code to my "slower, general purpose library"-code, but there is no point. It's comparing apples to oranges.

    I AM suggesting that you could implement the exact same functionality a little bit differently and get significantly better performance without sacrificing any generality.
    I would be very interested in those suggestions. Because until now, you haven't given any. All suggestions you have made DO sacrifice generality, so they don't apply.

    The Possible/CostsLittle argument is what leads to code bloat. There is always a cost and just because can doesn't mean that you should. These things add up.
    It's a bit weird that you are saying these things to me, because normally it's me saying these kinds of things (about PEAR). You saying these things about Eclipse is pretty strange. In my opinion (and in the opinion of many others) Eclipse is certainly not bloated at all.

    NO capability is lost. The simpler version would have a different simpler iterator
    As I explained earlier, capability IS lost.

    I am just trying to show why I thought it was bloated when I originally evaluated it.
    That's alright, of course. Comments are always welcome. However, to be honest I have no idea what to do with yours. They make no sense to me at all.

    Do you see how getRow in QueryResult is really just getCurrent in the Iterator class.
    Of course I see that; I designed it that way. It seems you don't see the iterator and the query result are separated on purpose. That is: intentionally.

    Your iterator class provides this capability and you should be using it. not getRow.
    In an earlier post you mentioned you knew what iterators are. This comment proves otherwise. I also read (in yet another post) that you read quite a lot of books on OOP. I applaud that, of course. But do you really understand what you've read? Because you're posts tell me you don't. (But then: who am I?)

    Vincent

  24. #24
    SitePoint Wizard gold trophysilver trophy
    Join Date
    Nov 2000
    Location
    Switzerland
    Posts
    2,479
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If I can just inject a comment, it seems Selkirks original criticism of the Iterators was that each one inherits from a parent that doesn't "do anything" itself, resulting in a performance hit.

    That in itself exposes a discussion that seems to divide many PHP coders (and also seems to relate to a current Java vs. .NET Petstore debate regarding use to design patterns, which is raging all over).

    PHP is in many ways a special case as a language, as much of it's native library is implemented in a procedural form (with a few exceptions like the Dom XML Extension and the dir class). Other features, like GET and POST data being accessed via global variables blur the case for particular design practices in PHP.

    My own view these days (after having wasted alot of time on code that was extremely hard to maintain) is that anything which improves a developers performance far outweighs any associated hit in application performance.

    Vincents Iterator classes strike exactly this nerve. PHP doesn't have an "abstract" or "interface" keyword so the common argument against his Iterators is either why inherit from a class that "serves no purpose" or why bother having an Iterator at all, given it's possible to implement this is native PHP.

    What I like about them, in their present form, is for a developer provided with Vincents API documentation and some code acting as a client to Eclipse, reading the client code will "make sense". The naming of the methods makes code that uses them intuitive to read. Any Iterator used will be clearly identifiable. Should it be necessary to swap one for another, for example moving the source of some data from a text file to a database table, the developer understands the "contract" that DataFileIterator and QueryIterator both come with and can predict the results of the change. Furthermore should it be necessary create a new Iterator for some other purpose (such as walking a XML structure which will be parsed using SAX), the task of the developer is easy, knowing exactly the rules the have to comply with.

    These may seem like trivial benefits and perhaps I'm just a slack developer but while working on a project that takes a few weeks / months, I find I tend to change styles and adopt different approaches to solving the same problem. What's more I may not even realise I'm solving the same problem. Having a framework like Vincents which identifies common problems I face every day and provides a uniform solution is extremely beneficial.

    Of course to gain that benefit I have to commit myself to using Eclipse and it's approach to solving problems but given that Eclipse focuses on data related tasks, I haven't tied myself to something that will limit my ability to do unusual things with the rest of my application.

    For me, the true value of the Iterators becomes apparent when you have to go back to some old code at a later date. Illustrating this with a thought experiment, that makes good sense to me, is to consider whether it's possible to replace a database with a web service as the source of data in the application (something that I might concievably want to do).

    Fetching data from a web service is a different problem to fetching from a database. One problem is you want to make as few "calls" to a web service as possible (avoiding the significant performance overhead of using HTTP over an unreliable network). It's necessary to fetch as much data as possible in a single call and store is somewhere locally so I don't need to repeat the call.

    The specifics of a class I use to do this will be quite significantly different from a database class performing a similar data fetching operation. If I directly used the API of the database classes throughout my application, there'll be much re-writing when switching to a web service.

    If instead I used the QueryIterator, I can create something like a SOAPIterator and simply instaniate this instead.

    Going back to the question of code bloat, although you may argue that Eclipses use of abstract / interface classes constitutes bloat, but if you look at any concrete classes in the library, their methods and coding is highly discrete and minimalistic. It may not provide code that executes faster but it does make it very easy for other developers to understand.

  25. #25
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally posted by voostind
    It's a bit weird that you are saying these things to me, because normally it's me saying these kinds of things (about PEAR). You saying these things about Eclipse is pretty strange. In my opinion (and in the opinion of many others) Eclipse is certainly not bloated at all.
    I know that you say these things. Thats why I posted.

    The first time I evaluated eclipse, I downloaded it straight from hotscripts, looked at the code for 5 minutes, drew my conclusions and deleted it.

    When I saw this thread, I searched for eclipse, found your website, read it, and then looked at the code.

    The reason I decided to comment was that I agree with many of the things you say on your website.

    There are a lot of other things that aren't even worth commenting on. (Like the event handler stuff)

    That's alright, of course. Comments are always welcome. However, to be honest I have no idea what to do with yours. They make no sense to me at all.
    I know. I am going to assume that you are open minded and that I am just failing to communicate. What I don't want to have to do is re-write the thing to make my point.

    I honestly thought my code example would be enough.

    Let me go into more detail regarding the iterator implementation. Your iterator implementation works on an "indexed" conceptual model.

    Your iterator interface works on a sequential access model:

    reset()
    next()
    IsValid()
    getCurrent()

    You cannot arbitrarily access elements using this interface. You cannot even find out what position you are at.

    furthermore, all of the things that you attempt to iterate over have native sequential access functions in the style of: move to the next position, return the element there or indicate that there are none left.

    arrays: next()
    databases: mysql_fetch_array()
    files: fread()
    directories: readdir()

    So, the native PHP functions use a sequential access interface. Your iterator class presents a sequential access interface. Yet, its internal implementation uses an indexed conceptual model. It maintains an index. It accesses the rows by index from the QueryResult. Eclipse has an impedance missmatch between conceptual models. This is bad.

    Client code (Sequential) => eclipse (indexed) => PHP (Sequential)

    There are two problems with the indexed model. First, it is less efficient. Second, it is less safe in a multi user environment.

    It is less efficient because it maintains an index which doesn't really serve an external purpose. It also requires that you get a count of the elements at the beginning. The sequential access model does not require that you get this count of records.

    It is less safe because when you get the count of elements at the beginning, and another user in another process adds or deletes records, your count is not longer correct.

    Some databases like mysql will protect you from this by caching the query results. Some won't. Take for example, the function mysql_unbuffered_query. With this query, you cannot access mysql_num_rows(). This mean that your QueryIterator implementation cannot work with queries generated from mysql_unbuffered_query. A QueryIterator that followed a sequential access conceptual model would. You shouldn't assume that I might not want to use this type of query.

    My code was supposed to illustrate how you can implement your Iterator interface using a sequential access model. The performance gain was supposed to be the "hook" that got you to pay attention to it. (oh, well.)

    There is one hurdle to your understanding. (Partly why you think you would lose functionality.)

    Of course I see that; I designed it that way. It seems you don't see the iterator and the query result are separated on purpose. That is: intentionally.
    Yes. i know it was intentional.

    There is an activation energy. Implementing a sequential access query is harder given the current relationship and implementation of QueryIterator and QueryResult. QueryResult becomes the natural place to implement a QueryIterator. The QueryIterator class becomes superfluous.

    If you stop thinking of QueryIterator as a class and start thinking of it as an interface, these problems melt away. (I feel zen like. Clear your mind. release your hangups and inhibitions.)

    Think of the QueryResult as the wrapper for the result resource from the query. When the result is multiple rows, you use the QueryResults iterator interface to access them.

    Now, for compatibility purposes, You implement QueryIterator as a pass-through adapter. Each method simply calls the equivalent method on the QueryResult that you pass to it. This maintains complete backward compatibility. You then deprecate the QueryIterator class. Its there, but you should not use it in the future.

    I have a bit more to say, but people are dragging me away from my computer to go eat lunch.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •