SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 58
  1. #1
    SitePoint Enthusiast matid's Avatar
    Join Date
    May 2005
    Location
    Knurow, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    ActiveRecord - dynamic way

    I'd like to implement ActiveRecord pattern in my application, however it want to keep it really simple:
    * You add database structure, let's say table posts with 3 columns: id, title, body.
    * You create class Post:
    PHP Code:
    <?php
    class Post extends ActiveRecord {}
    ?>
    That's all, you're free to go. The only problem is, that when I use:
    Post::find that is declared in ActiveRecord I cannot aquire the class that was called. Even debug backtrace shows it as ActiveRecord::find instead of Post::find.
    Do you have any idea to get past it? Or maybe creating PostFinder object is the way to go? Or maybe scaffoling?

  2. #2
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by matid
    The only problem is, that when I use:
    Post::find that is declared in ActiveRecord I cannot aquire the class that was called. Even debug backtrace shows it as ActiveRecord::find instead of Post::find.
    Do you have any idea to get past it? Or maybe creating PostFinder object is the way to go? Or maybe scaffoling?
    Hi. You can't get the name of a class that has been extended, from within the base class. There is a "hack" though by using a stack trace. But I'm pretty sure that only works in PHP5!

    I wanted to do exactly what you are doing but that was the only thing I couldn't figure out. I decided to go with an "ActiveRecordFinder" class. Having finder methods in a model always seemed a bit bloatalcious anyway. Something like:

    $people =& ARFinder::all('person', '*', 'name LIKE %?%', array('matid'));

    There is a project called LivePipe (http://livepipe.net/) that has another way of dealing with it in PHP 5. Something like:

    $post = model('Post')->find(1);

    -matt

  3. #3
    SitePoint Enthusiast matid's Avatar
    Join Date
    May 2005
    Location
    Knurow, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I code in PHP5 and I'll probably use some of the ideas described here: http://livepipe.net/docs/class/ActiveRecord
    Thanks for help

  4. #4
    SitePoint Evangelist jplush76's Avatar
    Join Date
    Nov 2003
    Location
    Los Angeles, CA
    Posts
    460
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    what you're trying to do is a rails type implementation which has been done already in php on trax http://www.phpontrax.com
    I have yet to be able to get phpontrax to work as the docs are nonexistent and I'm getting errors all over, however if you look at the source code you'll find an ActiveRecord.php class that does exactly what you're trying to do.

    check it out and learn from the source code.
    My-Bic - Easiest AJAX/PHP Framework Around
    Now Debug PHP scripts with Firebug!

  5. #5
    SitePoint Guru thr's Avatar
    Join Date
    Jun 2003
    Location
    Sweden
    Posts
    664
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    Hi. You can't get the name of a class that has been extended, from within the base class. There is a "hack" though by using a stack trace. But I'm pretty sure that only works in PHP5!
    If I got this right - you're wrong. To get the extended class out of a baseclass method you do this:
    PHP Code:
    <?php
    class {
        public function 
    getClass(){
            echo 
    get_class($this);
        }
    }
    class 
    extends { }
    $a = new A;
    $a->getClass(); // prints 'A'
    $b = new B;
    $b->getClass(); // prints 'B'
    ?>
    (If I did miss something - I'll blame it on my 39c fever ;p)

    Quote Originally Posted by mwmitchell
    I wanted to do exactly what you are doing but that was the only thing I couldn't figure out. I decided to go with an "ActiveRecordFinder" class. Having finder methods in a model always seemed a bit bloatalcious anyway.
    That's kinda the point of AR - encaspulate both the values and the logic of a type/object.

    Quote Originally Posted by mwmitchell
    $people =& ARFinder::all('person', '*', 'name LIKE %?%', array('matid'));

    There is a project called LivePipe (http://livepipe.net/) that has another way of dealing with it in PHP 5. Something like:

    $post = model('Post')->find(1);
    I'd seriously not consider to use a project that didn't even figure out the way to return an extend classname thru a superclass method ;p.

  6. #6
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by thr
    If I got this right - you're wrong. To get the extended class out of a baseclass method you do this:
    PHP Code:
    <?php
    class {
        public function 
    getClass(){
            echo 
    get_class($this);
        }
    }
    class 
    extends { }
    $a = new A;
    $a->getClass(); // prints 'A'
    $b = new B;
    $b->getClass(); // prints 'B'
    ?>
    (If I did miss something - I'll blame it on my 39c fever ;p)
    Yeah, but doesn't work with static calls, get well soon.

  7. #7
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by matid
    The only problem is, that when I use:
    Post::find that is declared in ActiveRecord I cannot aquire the class that was called. Even debug backtrace shows it as ActiveRecord::find instead of Post::find.
    Do you have any idea to get past it? Or maybe creating PostFinder object is the way to go? Or maybe scaffoling?
    If I understood you correctly, you're trying to call Post::find from itself, but you can't figure the name of the class you're in? To call a static method from within a class, just use self, as in self::find(). I can see no valid purpose why should an object know its own class name -- in fact, it seems to go against the very point of object orientation. In an object: if you need the reference to itself, use $this; if you need its class, use self; if you need it's parent's class, use parent. As simple as that.

  8. #8
    SitePoint Zealot
    Join Date
    Feb 2005
    Posts
    136
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by BerislavLopac
    If I understood you correctly, you're trying to call Post::find from itself, but you can't figure the name of the class you're in? To call a static method from within a class, just use self, as in self::find(). I can see no valid purpose why should an object know its own class name -- in fact, it seems to go against the very point of object orientation. In an object: if you need the reference to itself, use $this; if you need its class, use self; if you need it's parent's class, use parent. As simple as that.
    there are plenty of reasons to have the class name.

    the $this pointer does not exist when using a static method

    class A {
    static function foo() {
    return get_class( $this );
    }
    }

    echo A::foo(); // returns error as no instance of class A exists

  9. #9
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Actually I was mistaken -- self doesn't refer to the calling class. Bummer.
    PHP Code:
    class Foo
    {
        public static 
    $bar 'njanja';

        public function 
    baz()
        {
            echo 
    self::$bar;
        }

    }

    class 
    FooFoo extends Foo
    {
        public static 
    $bar 'blabla';
    }

    $f = new FooFoo();
    $f->baz();   // displays 'njanja' 
    Ain't this ridiculous?

  10. #10
    SitePoint Addict
    Join Date
    Aug 2003
    Location
    Toronto
    Posts
    300
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by BerislavLopac
    Actually I was mistaken -- self doesn't refer to the calling class. Bummer.
    PHP Code:
    class Foo
     
    {
         public static 
    $bar 'njanja';
     
         public function 
    baz()
         {
             echo 
    self::$bar;
         }
     
     }
     
     class 
    FooFoo extends Foo
     
    {
         public static 
    $bar 'blabla';
     }
     
     
    $f = new FooFoo();
     
    $f->baz();   // displays 'njanja' 
    Ain't this ridiculous?
    Maybe not entirely ridiculous. Static means bound to the class (that defines it). You can change the value in a derived class at runtime -- but as you show, not at compile time. What would it mean if FooFoo::$bar and Foo::$bar had different values? Why, $bar would look like a quasi-instance value in that case, not?

  11. #11
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jayboots
    Maybe not entirely ridiculous. Static means bound to the class (that defines it). You can change the value in a derived class at runtime -- but as you show, not at compile time. What would it mean if FooFoo::$bar and Foo::$bar had different values? Why, $bar would look like a quasi-instance value in that case, not?
    No, it would still be a class value, which is the whole point. Consider this:

    PHP Code:

    class Animal
    {
        protected static 
    $coverage 'skin';

        public function 
    getCoverage()
        {
            return 
    self::$coverage;
        }

    }

    class 
    Fish extends Animal
    {
        protected static 
    $coverage 'scales';
    }

    class 
    Bear extends Animal
    {
        protected static 
    $coverage 'fur';
    }

    $f = new Bear();
    echo 
    $f->getCoverage(); 
    So all our animals are covered in skin...

  12. #12
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There was a thread about this a while back, the concensus of which was; it's possible to get the name of the calling class in PHP4 by using the call stack, but it's currently impossible to do it at all in PHP5.

  13. #13
    SitePoint Wizard Ren's Avatar
    Join Date
    Aug 2003
    Location
    UK
    Posts
    1,060
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees
    There was a thread about this a while back, the concensus of which was; it's possible to get the name of the calling class in PHP4 by using the call stack, but it's currently impossible to do it at all in PHP5.
    It's not impossible in PHP5. Just highly unpractical, using the call stack to reopen the source file, and to locate which line the call was made. For the usual Class::method() syntax. Anything more complicated (call_user_func*() etc) it is almost impossible.

  14. #14
    SitePoint Enthusiast matid's Avatar
    Join Date
    May 2005
    Location
    Knurow, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    AFAIR static::method() will be introduced to fix this behaviour, however I don't expect to see it before PHP6

    The only way I was able to get it work was to use requested classes list from my autoloader and figuring out which call on the list was the one I wanted (based on call order).

  15. #15
    SitePoint Addict
    Join Date
    Aug 2003
    Location
    Toronto
    Posts
    300
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by BerislavLopac
    No, it would still be a class value, which is the whole point. Consider this:

    PHP Code:
           
           
    class Animal
           
    {
               protected static 
    $coverage 'skin';
           
               public function 
    getCoverage()
               {
                   return 
    self::$coverage;
               }
           
           }
           
           class 
    Bear extends Animal
           
    {
               protected static 
    $coverage 'fur';
           }
           
           
    $f = new Bear();
           echo 
    $f->getCoverage(); 
    So all our animals are covered in skin...
    Hmmm. AFIAC that is not an appropriate use of statics. You really want an instance object (and data) in this case; yes, you can specialize behaviour of static classes (which is the point of using statics in the first place -- encapsulization of pure behaviour) but because static data is tied to the defining class, you probably should not use statics to hold specializations of class data.

    Again, static data is bound to the defining class only and I agree that the way self:: works is rather funky. Let us reconsider some different versions of your example:

    PHP Code:
    class Animal
          
    {
              protected static 
    $coverage 'skin';
              public function 
    getCoverage() { return self::$coverage "\n"; }
          }
          
          class 
    Fish extends Animal
          
    {
              protected static 
    $coverage 'scales';
              public function 
    setCoverage($coverage) { self::$coverage $coverage; }
          }
          
          
    $a = new Animal;
          
    $f = new Fish;
          echo 
    $a->getCoverage();
          echo 
    $f->getCoverage();
          
    $f->setCoverage('scales');
          echo 
    $a->getCoverage();
          echo 
    $f->getCoverage(); 
    That prints something you might not expect:
    skin
    skin
    skin
    skin

    However, if you either change setCoverage() to use parent:: instead of self:: (so it points to the proper static data) or you remove the protected static $coverage = 'scales'; line -- then you get:

    skin
    skin
    scales
    scales

    probably also unexpected. Finally:

    PHP Code:
    class Animal
          
    {
              protected static 
    $coverage 'skin';
              public function 
    getCoverage() { return self::$coverage "\n"; }
          }
          
          class 
    Fish extends Animal
          
    {
              protected static 
    $coverage 'scales';
              public function 
    getCoverage() { return self::$coverage "\n"; }
          }
          }
          
          
    $a = new Animal;
          
    $f = new Fish;
          echo 
    $a->getCoverage();
          echo 
    $f->getCoverage(); 
    yields:

    skin
    scales

    So you can see is that depending on the class where the self:: is defined (as opposed to where in the hierarchy it is called from), you end up pointing to different (probably unexpected) static data. Statics are very unlike objects in this way.

    Never-the-less, I can't imagine using static data on an object instance -- it makes no sense to me to do so. ie. use static data for static classes and expect that the data will be shared across the hierarchy. Then again, I don't see much point in extending static classes. If there is need for specialization, that structure is probably a better candidate to be an object.

    Best Regards.

  16. #16
    SitePoint Enthusiast matid's Avatar
    Join Date
    May 2005
    Location
    Knurow, Poland
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jayboots
    If there is need for specialization, that structure is probably a better candidate to be an object.
    Not always. In Fowler's ActiveRecord find is a static method that is used to return an instance of the same class. The only difference is that he codes simple object (Person in his case) manually - we want it to be automatic without scaffolding.

  17. #17
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jayboots
    Never-the-less, I can't imagine using static data on an object instance
    I agree here, but what if you want to know what are birds covered with? The answer should be "feathers" even thought there is not an instance of the Bird class available. But in my example above, Bird::getCoverage() would yield "skin".

    Quote Originally Posted by jayboots
    use static data for static classes
    But what is a static class in reality? It makes sense to me that some information is available about a type of objects without having to have an instance of it.

  18. #18
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by thr
    If I got this right - you're wrong. To get the extended class out of a baseclass method you do this:
    PHP Code:
    <?php
    class {
        public function 
    getClass(){
            echo 
    get_class($this);
        }
    }
    class 
    extends { }
    $a = new A;
    $a->getClass(); // prints 'A'
    $b = new B;
    $b->getClass(); // prints 'B'
    ?>
    (If I did miss something - I'll blame it on my 39c fever ;p)

    That's kinda the point of AR - encaspulate both the values and the logic of a type/object.
    Yes I meant you can't if the class that's being access via static. I realize that the active record implements data and behaviour, but because you can't use the static thing, it seems strange to instantiate something, to have it return another instance of itself (or collection). That's why a seperate finder seems cleaner?

    -m

    p.s. the livepipe project is atually pretty clever.

  19. #19
    SitePoint Addict
    Join Date
    Aug 2003
    Location
    Toronto
    Posts
    300
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by matid
    Not always. In Fowler's ActiveRecord find is a static method that is used to return an instance of the same class. The only difference is that he codes simple object (Person in his case) manually - we want it to be automatic without scaffolding.
    I can agree with this when the purpose is pure scaffolding. Unfortunately, until ___CLASS__ does the right thing in PHP static classes, this doesn't seem practical. FWIW, I deal with this using a naming convention and autoloaders; eg:

    $user = new ADC_User;

    This then either loads a custom class that extends my ActiveRecord (and configures itself as required based on the class name: User) or automatically creates the class if a custom file is not found.

    Quote Originally Posted by BerislavLopac
    I agree here, but what if you want to know what are birds covered with? The answer should be "feathers" even thought there is not an instance of the Bird class available. But in my example above, Bird::getCoverage() would yield "skin".
    Yes, because your example implicitly uses the Animal::getCoverage() method and that method uses self::$coverage to return the static stored in the Animal class (as that is where self:: points to in the Animal::getCoverage() method even though it is called via an instance of Bird). I show that you can get around this, but it is much easier to represent by accepting that $coverage is really object data.

    Quote Originally Posted by BerislavLopac
    But what is a static class in reality? It makes sense to me that some information is available about a type of objects without having to have an instance of it.
    I do see your point, but the way I see it, static data on a static class is "meant" as a private area to support the work of the static methods (ie: persistant scratch) -- not as a means to store information about type or instance. After all, you even say that you want to learn information about the type of objects while statics are not objects -- they are the classes themselves. A small but important point . One way around this: provide concrete methods that hardcode data in extended static classes. Of course, that sucks -- a real object would be much more natural, yes?

  20. #20
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jayboots
    After all, you even say that you want to learn information about the type of objects while statics are not objects -- they are the classes themselves. A small but important point .
    Exactly -- I want to learn information about a type. And a class is a type -- that's the whole point of classes.

    But I think I see your point now -- if I want to know about a generic class, I want to know about the generic class's instance... Well, I guess OOP and real world don't mix just as much as I hoped...

  21. #21
    SitePoint Guru thr's Avatar
    Join Date
    Jun 2003
    Location
    Sweden
    Posts
    664
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    An ugly but workable hack is to make the PersonFinder/etc. a Singleton - it's as close to a static class as we can get today and to be able to get the class-name back - example:


    PHP Code:
    <?php
    $pf 
    PersonFinder::instance();
    $person1 $pf->findByPk(1);
    ?>

  22. #22
    SitePoint Addict
    Join Date
    May 2003
    Location
    The Netherlands
    Posts
    391
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jayboots
    ...while statics are not objects -- they are the classes themselves ...
    Exactly, AFAIK there is a huge difference between self and this. While this would point to an object instance, self points to the class signature, which is generic for any instance of that class.
    Quote Originally Posted by jayboots
    ... probably also unexpected
    To me, your examples work just as expected.
    Quote Originally Posted by PHP Manual
    When using an explicit class name the method is already identified completely and no inheritance rules apply. If the call is done by self then self is translated to the current class, that is the class the code belongs to. Here also no inheritance rules apply.
    http://www.php.net/manual/en/language.oop5.static.php
    There’s more than one way to skin a cat.

  23. #23
    SitePoint Guru thr's Avatar
    Join Date
    Jun 2003
    Location
    Sweden
    Posts
    664
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    p.s. the livepipe project is atually pretty clever.
    I downloaded and installed LivePipe and read some of the source - they got some good idea sure - but most/some of the code is just... awfull.

  24. #24
    SitePoint Guru thr's Avatar
    Join Date
    Jun 2003
    Location
    Sweden
    Posts
    664
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    After some reading and thinking I'd have to say that the Active Record pattern (the way Rails did it) - just isn't ment for php. You get a much cleaner design with Data Accessors + Data Mappers(or one universal data mapper)

  25. #25
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by thr
    After some reading and thinking I'd have to say that the Active Record pattern (the way Rails did it) - just isn't ment for php. You get a much cleaner design with Data Accessors + Data Mappers(or one universal data mapper)
    The problem is that Rails doesn't use static calls, it uses Ruby's class methods, which are dynamic calls to the class object. The subtle differences between the two means that this approach is a fair bit easier in rails than in php. Still, there's nothing wrong with using ActiveRecord along with finder objects, which is an approach suggested in Fowler's PoEAA, and a good fit for PHP's abilities.


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
  •