SitePoint Sponsor

User Tag List

Page 1 of 4 1234 LastLast
Results 1 to 25 of 118

Thread: ActiveRecords

Hybrid View

  1. #1
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    ActiveRecords

    Hi!

    I've been reading up on ActiveRecords and have a few questions.

    1. What are the cons of using it? Most articles seems to be written from a Ruby perspective and only speek of the positives. The advantages I see are basically that you don't need to write specific inserts/updates/deletes and you rely on finders to do most of the selection. Associations are probably powerful as well, but I have yet to study them in detail. Surely, there must be a downside as well?

    2. Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?

    3. I have a base ActiveRecord class that all other records inherit from. In the base class I have my save() and delete() functions. A record represents a row in a table. Now, the table-columns need to be declared class members of the record, so the generic save() function knows what fields to insert into.

    To separate these properties from other ActiveRecord properties, such as $table or $hasMany, I created an array called $properties where the fields are stored. Like so:
    PHP Code:
    class ActiveRecord
    {
        protected 
    $_table# name of table
        
    protected $_properties = array(); # a record's properties
        
    public function __construct($properties = array())
        {
            foreach (
    $_properties as $property => $value)
            {
                
    $this->_properties[$property] = $value;
            }
        }

    Is that a good idea? I don't see how else to do it.

    Now, if people could set whatever keys they wanted into the array, the save() function would fail (it would try to update fields that don't exist in the table). Because of that, each "column" needs to be declared in the extending Record class:
    PHP Code:
    class Blog extends ActiveRecord
    {
        protected 
    $_properties = array('id' null'title' null'text' null);

    And then I use the __set() method in the base ActiveRecord class like so:
    PHP Code:
    public function __set($property$value)
    {
        if (
    array_key_exists($property$this->_properties))
        {
            
    $this->_properties[$property] = $value;
        }

    It's been hard trying to find any good articles about this, so I'd appreciate any input. I'm still waiting for my copy of PoEAA.
    Last edited by pakmannen; Sep 6, 2007 at 08:50.

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pakmannen View Post
    What are the cons of using it? Most articles seems to be written from a Ruby perspective and only speek of the positives. The advantages I see are basically that you don't need to write specific inserts/updates/deletes and you rely on finders to do most of the selection. Associations are probably powerful as well, but I have yet to study them in detail. Surely, there must be a downside as well?
    Depends on what you compare against. ActiveRecord is one way (pattern) of encapsulating data access. This can help to simplify your application, by creating an abstraction. It also has the benefit of greater flexibility between data access and business logic. One consequence of this is, that you can replace the data access layer with a different implementation, without changing the rest of your application.

    ActiveRecord is a simple way of separating data access from business logic. It can quickly become cluttered. A table data gateway or a data mapper solves this task more elegantly, but are also more complex patterns. Whether you need to use them, depends on the complexity of your application, as well as personal taste.

    Quote Originally Posted by pakmannen View Post
    Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.

  3. #3
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    It also has the benefit of greater flexibility between data access and business logic ... ActiveRecord is a simple way of separating data access from business logic
    Let me see if I understand these terms correctly. Data access = the layer that access data from the database, that is, the finders? Business logic = the layer that inserts/updates/deletes from the database, the ActiveRecord?

    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    It seems kind of stupid to create an object whose sole purpose is to return another object. Also, I think Fowler says somewhere that Finders should be static methods? What's so bad about finders being "global"?

  4. #4
    SitePoint Member
    Join Date
    Jul 2006
    Location
    Prague, Czech republic
    Posts
    16
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pakmannen View Post
    Let me see if I understand these terms correctly. Data access = the layer that access data from the database, that is, the finders? Business logic = the layer that inserts/updates/deletes from the database, the ActiveRecord?
    As I see it:
    Data access = the layer that works with database tables and records.
    Business logic = the layer that works with blogs and users.

  5. #5
    SitePoint Addict
    Join Date
    Aug 2007
    Location
    GR
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    Statics are used when you want a set of functions that are not associated with an object.

  6. #6
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by _Steve_ View Post
    Statics are used when you want a set of functions that are not associated with an object.
    True. And if you program object oriented, all functions are associated with an object.

    Quote Originally Posted by pakmannen View Post
    What's so bad about finders being "global"?
    Global symbols makes the code inflexible, and introduces dependencies, which aren't explicit. The latter can lead to unforeseen side effects. It's actually quite hard to explain why globals are bad, with out getting very abstract and academic. This is because global symbols aren't as big a problem in a simple system (Which programming examples always are).

  7. #7
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok then.... so when it comes to web development, should we use SED instead?

  8. #8
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Statics are essentially global variables, and therefore a bad choice. You should rather create instances of your finders.
    Instances are variables, frequently global, and therefore a bad choice

    (btw, Fowler uses static methods without hesitation ...)

  9. #9
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    Instances are variables, frequently global, and therefore a bad choice
    Instance variables aren't global unless you declare them so. Static variables are always global. I have no problem with static variables, if they are local in scope, which they are in languages such as Ruby (Correct me if I'm wrong - I never wrote a single line of Ruby code).

    Quote Originally Posted by Mastodont View Post
    Fowler uses static methods without hesitation ...
    Mind you, Fowler is a technical writer, who often shows examples to make one particular point. In order to make this point clear, he may deliberately chose to neglect other aspects.

  10. #10
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm

  11. #11
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by BerislavLopac View Post
    In other words, a collection is a separate object from its items, and there is "findAll" static calls, as the Item class is not (and should not be) responsible for gathering collections of itself.
    Or you use a finder object, which you make an instance of and then use method calls;

    Quote Originally Posted by kyberfabrikken View Post
    I have no problem with static variables, if they are local in scope, which they are in languages such as Ruby (Correct me if I'm wrong - I never wrote a single line of Ruby code).
    Actually, ruby doesn't have static variables at all, and I haven't found any situations where I'd need on over simply using an instance variable.

    Quote Originally Posted by phpimpact View Post
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm
    I'm not terribly familiar with the Zend framework, but it seems very much influenced by Java. Which, while certainly a proven approach to OOP, is not my favorite.

  12. #12
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    There are more static methods in the Zend framework than messages in this forum. Don't forget, OOP is a programming paradigm
    The Zend framework (V1.0) contains some 309 static methods. This forum has over 7,000 threads.

  13. #13
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Instance variables aren't global unless you declare them so. Static variables are always global.
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    Well, pakmannen wrote about static METHODS, not VARIABLES. If a file containing class with static methods is not included yet, this class could not be global.

    Sometimes it looks like there are two kinds of Sitepoint's religion: static is always Evil, dependency injection is always Good.

  14. #14
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Mastodont View Post
    Well, pakmannen wrote about static METHODS, not VARIABLES.
    Global (static) functions are perhaps not as problematic as global variables, but they still cause strong coupling. This makes the code inflexible.

    Quote Originally Posted by Mastodont View Post
    Sometimes it looks like there are two kinds of Sitepoint's religion: static is always Evil, dependency injection is always Good.
    Religion is - per definition - irrational. I find it quite rational to avoid global symbols, if the code is to be maintainable.

  15. #15
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Umm...

    > Let me see if I understand these terms correctly.

    In the case of the Active Record, what is particular special about it, is that business logic also resides on the Active Record in question, whereas with another domain pattern, as suggested by Kyber, the business logic would otherwise be encapsulated elsewhere.

    Business logic may be something such as to verify that a user is logged in for example? That is, a comparison of a database row against a users credentials, such as username and password.

    Another example, would be to keep a tally of a number of comments against a given blog post. You should now have a better picture of what I mean by business logic?

    The problem in my view is that Active Record can easily become bloated. That and that the Active Record in my mind, wasn't particularly well thought out in regards to database table relationships.

    As to RoR, if you do use that framework, your basically stuck with Active Record, as far as I can tell. I don't use RoR so that isn't my problem

    > I'm still waiting for my copy of PoEAA.

    I'm still waiting on the follow up, which goes further into domain modeling, and how patterns affect the design of a domain.
    Last edited by Dr Livingston; Sep 6, 2007 at 10:45. Reason: Added comment

  16. #16
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pakmannen View Post
    1. What are the cons of using it?
    There are three main ones:

    The first is that you end up with a 1 to 1 relationship between models and database tables. This can be problematic if your model frequently need to pull from multiple tables, or when you're dealing with a legacy database schemas.

    The second is performance; if your activerecord implementation isn't well designed, you can often run into 1+N problems, where you're performing multiple queries when you only really need two.

    The third is that you're mixing your database access with your business logic, which bothers some people.

    Speaking of business logic, I don't authentication or authorization are good examples, as I would consider those to be application logic. Business logic is things like calculating shipping costs based on client location and package size.

    Quote Originally Posted by pakmannen View Post
    2. Because of the whole static problem with php, I created a separate Finder class with static findAll, findById, findBySQL etc methods. I call these from my controllers like so:
    PHP Code:
    $blogs Blog::findAll(); # Ruby way
    $blogs Finder::findAll('Blog'); # My way 
    This seems acceptable to me. How are others coping with this problem?
    It's important to note that there are no static calls in ruby; classes are objects, and Blog.findAll() is a class method (as opposed to an instance method).

    My problem with this approach (apart from the other issues with static calls) is that you can't write specific finder methods for your different models. For example, you might want to Blog.findLatestPosts(), and there's no simple way to do that with static calls. So the static approach seems convenient at first because you're saving yourself the trouble of creating objects, but it's very inflexible.

    The solution I'm considering is to use a registry of finders, so that you don't have to create a new object for each find call. Something like

    PHP Code:

    $registry
    ->finders->blog->findLatestPosts(); 
    Quote Originally Posted by pakmannen View Post
    3. I have a base ActiveRecord class that all other records inherit from. In the base class I have my save() and delete() functions...
    That's pretty much what I'm doing; a have an array of properties, and a separate array of column objects. The column objects are generated automatically via a DESCRIBE query, and provide additional information, such as default values. When the save method is called, I iterate over the columns array and save the relevant properties. The means that the model can have properties that are not present in the table, and it won't cause any problems (they're simply not saved)

  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 33degrees View Post
    My problem with this approach (apart from the other issues with static calls) is that you can't write specific finder methods for your different models. For example, you might want to Blog.findLatestPosts(), and there's no simple way to do that with static calls. So the static approach seems convenient at first because you're saving yourself the trouble of creating objects, but it's very inflexible.
    I have designed a class "supertype" (ideally probably an interface, in practice an abstract class), called "collection", which holds the information about a, well, collection of objects. The data is collected (from the db) at some point and (in current implementation) held internally as an array; when a particular item is requested the collection instantiates a specific item class (which currently employs active record, but it doesn't have to).

    In other words, a collection is a separate object from its items, and there is "findAll" static calls, as the Item class is not (and should not be) responsible for gathering collections of itself.

    I am a strong proponent of strong class vs. instance dichotomy, which many people tend to neglect. In my experience -- both programming and real-life -- it is extremely rarely that a type of objects does anything without it being done by its actual representatives. Static members have their place, but in almost all cases as programmer's shortcuts and conveniences, and not as actual class properties.

  18. #18
    SitePoint Enthusiast
    Join Date
    Aug 2007
    Posts
    92
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Lo and behold, my copy of PoEAA arrived today. I'm ploughing through the first chapters now, which deals with domain logic and mapping to databases. It's nice to finally understand a bit about the terminology.

    The patterns he talks about are Row Data Gateway, Table Data Gateway, Active Record and Data Mapper. Active Record and Row Data Gateway are identical, except that Active Records also include domain logic. That is to say:
    PHP Code:
    class User # this could be a row data gateway...
    {
        
    $name;
        
    $email;

        function 
    insert();
        function 
    isOnline(); # what's this? domain logic! means we've got an active record

    Which is basically what Dr Livingstone already said. I can see that some people would prefer to keep the domain logic separate.

    You could still use Active Records, Row Data Gateways and Table Data Gateways when your Domain Model evolves and no longer corresponds with the database table structure, but it seems that a Data Mapper would be the logical choice in such a scenario. They do seem more complex though, so I think I will focus on the other patterns for now.

    Also, as for Table Gateways vs Row Gateways/Active Records I guess it depends on if your application mostly deals with result sets or rows?

    I know I completely ignored the static debate but I'm too tired right now..

  19. #19
    SitePoint Addict
    Join Date
    Aug 2007
    Location
    GR
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So a private static var or method is global?

  20. #20
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by _Steve_ View Post
    So a private static var or method is global?
    Yes.

    I can see how that may sound weird at first, but the static variable belongs to a class, and this class is a global symbol. The special case about a private static variable is, that it isn't directly accessible from your code. Even then, it still is a global symbol. If you change the variable (Which can only be done indirectly), it will have consequences for all parts of the code. The thing, that makes it a global symbol is, that it has the same meaning from all places in your application. The fact, that it isn't directly accessible isn't relevant. For example, let's say you had the following class, encapsulating database access:
    PHP Code:
    class Database
    {
      static private 
    $connection;

      static public function 
    Connect($host$user$password$database) {
        
    self::$connection mysql_connect($host$user$password);
        
    mysql_select_db($databaseself::$connection);
      }

      static public function 
    Query($sql) {
        return 
    mysql_query($sqlself::$connection);
      }

    It's a na´ve example, but try to bear with me - Examples usually are.

    Now assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global. While this example may appear a bit conceived, it's exactly how the legacy mysql_* functions work in PHP. Most programs don't pass the (optional) $link argument along to the mysql_* functions. This will then, implicitly, use an internal (private, if you may) value. This is causing problems when you try to make two applications work together.

    Quote Originally Posted by Mastodont View Post
    What about factory object - do you always create new factory or have you got one global factory??
    That's a good point. Because of how the language is constructed, you have to use a global symbol, to create instances. Eg. a class is a global symbol. Factories can be used to decouple this dependency, but eventually they can only minimise the impact - not completely eliminate it.

    Quote Originally Posted by Mastodont View Post
    What about constants - they are always global
    And that they are. I would never use a constant for anything, which isn't truly constant. For example, I wouldn't recommend this:
    PHP Code:
    define('DB_USERNAME''root'); 
    Whereas I can live with this:
    PHP Code:
    $result->fetch(PDO::FETCH_ASSOC); 
    Quote Originally Posted by Jasper Bekkers View Post
    Saying that something is bad, per definition, is just like religion, isn't it?
    Only if I refuse to give any argument, other than the will of God.

    Quote Originally Posted by pakmannen View Post
    Alright, so after reading a bit in PoEAA I've decided that Active Record makes sense for my purpose. I have a 1:1 relationship between my database and my models so a data mapper would be overkill. And I'm not bothered about mixing my domain logic in the Active Record. As a matter of fact, once you generalise the save/delete/get/set methods, there's not much left in them but the domain logic anyway.
    It depends on the type of application. Many web applications revolves around retrieving, storing and presenting data. When this is the case, an active record may be the best choice, because the complexity doesn't warrant splitting the model up in two distinct layers.

    Quote Originally Posted by pakmannen View Post
    And let's keep it civil folks, don't want this to end up like the last one.
    Yes, this is getting a bit out of control.

  21. #21
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    ... assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global ...
    Same class from the SAME storage??

  22. #22
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    It's a naïve example, but try to bear with me - Examples usually are.

    Now assume, that you had two applications, which used different databases. If the both used the same class, they would get in conflict, because the $connection property of Database is global. While this example may appear a bit conceived, it's exactly how the legacy mysql_* functions work in PHP. Most programs don't pass the (optional) $link argument along to the mysql_* functions. This will then, implicitly, use an internal (private, if you may) value. This is causing problems when you try to make two applications work together.
    You can connect to different databases using the same class, you only need to change the example you posted above:

    PHP Code:
    class Database
    {
        protected static 
    $_instance = array();
        protected 
    $_connection false

        public static function 
    getInstance($handler
        {
            if (!isset(
    self::$_instance[$handler])) {
                
    self::$_instance[$handler] = new self();
            }
            
            return 
    self::$_instance[$handler];
        }
        
        public function 
    connect($host$user$password
        {
            
    $this->_connection mysql_connect($host$user$password);
        }

    Last edited by phpimpact; Sep 8, 2007 at 13:56.

  23. #23
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by phpimpact View Post
    You can connect to different databases using the same class, you only need to change the example you posted above:
    Sure you can. I was only trying to show that a private static property is indeed a global symbol. Whether anybody would ever implement a database connection object as a static class is a different story.

    Quote Originally Posted by Mastodont View Post
    Same class from the SAME storage??
    Not sure, what you mean?

  24. #24
    SitePoint Addict
    Join Date
    Aug 2007
    Location
    GR
    Posts
    352
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Sure you can. I was only trying to show that a private static property is indeed a global symbol. Whether anybody would ever implement a database connection object as a static class is a different story.
    Now, you make me think. My db class is all static. Why? Because I only need one connection for one database and the connection private variables will never change and the meaning of private is that only the class can change the variables, I know you know it but you put it with another meaning.
    I've never run into the case of having the $conn object interact with 2 dbs so I stick to static. It's just what fits the project, because at work (.NET) there are some times where my db class must be instantiated.

    Sticking to PHP things are different. Whilst you say they are global, you have to include the file first, just like you do with other classes, which in turn when you instantiate, if they have public vars - they are accessible through out your script. I can compare PHP's includes to namespaces somehow. But old-fashioned $_GLOBALS are pure globals, they exist for all the application.

    Did I convince you?

  25. #25
    SitePoint Addict
    Join Date
    Sep 2006
    Posts
    232
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree with Fowler, the author. Because if I need to coordinate actions across a system I'll definitely use the singleton pattern, and for that I need a static method.

    Now, when it comes to Singletons vs Global Variables, I recommend using Singletons. They are better because they don't pollute the global namespace with unnecessary variables. And they permit lazy allocation and initialization, where global variables in many languages will always consume resources. Not only in PHP, in Java, C# and C++ as well.

    The Zend framework (V1.0) contains some 309 static methods. This forum has over 7,000 threads.
    There you have it, 309


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
  •