SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,182
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)

    Wish php had double class extension...

    So maybe someone can suggest an alternative set up to what I have:

    Code PHP:
    class ftp {} // handles opening ftp connections, listing files, downloading files, etc
    class mongo_conn {} //handles mongodb connections
    class dur_files extends ftp {} //dur is a type of file I regularly deal with, allows me to list dur files, download them locally, extract them (gz) and then calls dur_import
    class dur_import extends mongo_conn {} // handles the import of a file from dur_files, ideally I'd extend dur_files as well as mongo_conn, but I cant, so Im calling this class from within dur_files

    10,000' view is that I need to be able to list files that are in a directory, determine if they are loaded into mongodb, pull them down, extract and then load line by line (all this is programmed) but I'm running into organization / extension issues.

  2. #2
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,026
    Mentioned
    64 Post(s)
    Tagged
    0 Thread(s)
    Certain problems of multiple inheritance can now be dealt with using PHP Traits as of PHP 5.4

  3. #3
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,182
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)
    This seems like an ugly hack for Zend to have implemented.. I'm trying it out now

  4. #4
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,182
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)
    Especially since I can't use the trait directly? Boo Zend, just boo.

  5. #5
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,026
    Mentioned
    64 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by K. Wolfe View Post
    This seems like an ugly hack for Zend to have implemented.. I'm trying it out now
    PHP has ugly hacks? Say it ain't so Joe.

  6. #6
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,182
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)
    1,000 internet points for Michael

  7. #7
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,131
    Mentioned
    152 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by K. Wolfe View Post
    So maybe someone can suggest an alternative set up to what I have:

    Code PHP:
    class ftp {} // handles opening ftp connections, listing files, downloading files, etc
    class mongo_conn {} //handles mongodb connections
    class dur_files extends ftp {} //dur is a type of file I regularly deal with, allows me to list dur files, download them locally, extract them (gz) and then calls dur_import
    class dur_import extends mongo_conn {} // handles the import of a file from dur_files, ideally I'd extend dur_files as well as mongo_conn, but I cant, so Im calling this class from within dur_files

    10,000' view is that I need to be able to list files that are in a directory, determine if they are loaded into mongodb, pull them down, extract and then load line by line (all this is programmed) but I'm running into organization / extension issues.
    You really don't want to inherit ftp and mongo_conn together anyway, nor really do you want to do that with dur_files and dur_import? Why? Because they are not related. ftp is not a mongo_conn and the opposite isn't true either, mongo_conn is not an ftp.

    Really you should use dependency injection for this (probably even true for dur_files and dur_import, as I bet dur_files is not an FTP and dur_import is not a mongo_conn. However, I bet dur_files needs FTP and dur_import needs dur_files and mongo_conn.

    I'd personally lay it out like so:
    PHP Code:
    class dur_files
    {
      private 
    $ftp;
      public function 
    __construct($ftp)
      {
        
    $this->ftp $ftp;
      }
    }

    class 
    dur_import
    {
      private 
    $files;
      private 
    $db;
      public function 
    __construct($db$files)
      {
        
    $this->db $db;
        
    $this->files $files;
      }

    This way if you need to utilize another database, you can pass that forward too and as long as they have the same method implementation, it just works.

  8. #8
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    I agree with cpradio. Is it correct to say that a file "is-a" transfer protocol? This is a case where composition would be better than inheritance.

    Here's how I might put it together.

    First, your connection classes.

    PHP Code:
    class FtpConnection
    {
        
    // ...
    }

    class 
    MongoConnection
    {
        
    // ...

    We want to make sure these two classes can be used interchangeably, so we're going to make sure they both support the same interface.

    PHP Code:
    interface ConnectionInterface
    {
        public function 
    connect();
        
        public function list();
        
        public function 
    get();
        
        
    // or whatever you want the methods to be
    }

    class 
    FtpConnection implements ConnectionInterface
    {
        
    // implement all the methods from ConnectionInterface using FTP
    }

    class 
    MongoConnection implements ConnectionInterface
    {
        
    // implement all the methods from ConnectionInterface using Mongo

    Now you can make a one-time decision to instantiate either FtpConnection or MongoConnection, and all your code from that point forward can be ignorant of which kind of connection you're using.


    If you have common ways that you handle remote files, then you could create some sort of remote file manager class.

    PHP Code:
    class RemoteFileManager
    {
        private 
    $connection;
        
        
    // this class can and probably should be ignorant of the kind of connection we're using
        // so it expects an existing connection object to be passed to it
        // this is the dependency injection pattern cpradio was talking about
        
    public function __construct(ConnectionInterface $connection)
        {
            
    $this->connection $connection;
        }
        
        
    // ...

    "First make it work. Then make it better."

  9. #9
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    I re-read your comments about what each class is supposed to do, and I realized that what I posted doesn't really work the same way, but hopefully it helps to convey the gist of composition over inheritance.
    "First make it work. Then make it better."

  10. #10
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,131
    Mentioned
    152 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    I agree with cpradio. Is it correct to say that a file "is-a" transfer protocol? This is a case where composition would be better than inheritance.

    Here's how I might put it together.
    I actually liked where you went with it, other than I'm not sure I'd give the same interface between a file transfer protocol and a database protocol. I would have given two different interfaces, so if you switched from FTP to Telnet, or Curl, or SCP all of those could be built the same.

    I don't necessarily think the same is true for MongoDB, MySQL, Postgres, Oracle, etc, however, all of those would have the same process as each other, just not the same as FTP, Telnet, etc.

    I really wish people would utilize interfaces more often (this comes from my .NET background). Interfaces are a godsend for APIs and forcing classes to abide by a specific implementation. It is unfortunately so many get it wrong or refuse to use it.

    @K. Wolfe ; one thing that really has helped me choose between composition and inheritance is using the "is a" rule, but on top of that, if I ever had the thought, "Man, I wish I could inherit both X and Y", I know I screwed up somewhere and I need to re-evaluate what I've done. Inheritance complicates things, and more inheritance only leads to further complication.

    Let me leave you with this thought. Where I previously worked a contractor built our original web service that allowed third parties to get quotes from our system. The VERY base class of the 13 level inheritance was named ErrorClass (I'm not kidding!). The only thing I can tell you now, is at least he knew where his code was heading. Everything sucked, it threw more errors than returning success messages, etc. After reworking it for a couple of years (it took us years to get an architecture that could easily be swamped out), our largest inheritance level was 3. We only needed that third level for a special implementation of a project and once everything was transferred over, it went down to 2, but I think this will bring home the point (inheritance isn't bad, but it's complicated, and you need to understand why you are doing it and you are doing it for the right reasons).

  11. #11
    Always A Novice bronze trophy
    K. Wolfe's Avatar
    Join Date
    Nov 2003
    Location
    Columbus, OH
    Posts
    2,182
    Mentioned
    65 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    I agree with cpradio. Is it correct to say that a file "is-a" transfer protocol? This is a case where composition would be better than inheritance.

    Here's how I might put it together.

    First, your connection classes.

    PHP Code:
    class FtpConnection
    {
        
    // ...
    }

    class 
    MongoConnection
    {
        
    // ...

    We want to make sure these two classes can be used interchangeably, so we're going to make sure they both support the same interface.

    PHP Code:
    interface ConnectionInterface
    {
        public function 
    connect();
        
        public function list();
        
        public function 
    get();
        
        
    // or whatever you want the methods to be
    }

    class 
    FtpConnection implements ConnectionInterface
    {
        
    // implement all the methods from ConnectionInterface using FTP
    }

    class 
    MongoConnection implements ConnectionInterface
    {
        
    // implement all the methods from ConnectionInterface using Mongo

    Now you can make a one-time decision to instantiate either FtpConnection or MongoConnection, and all your code from that point forward can be ignorant of which kind of connection you're using.


    If you have common ways that you handle remote files, then you could create some sort of remote file manager class.

    PHP Code:
    class RemoteFileManager
    {
        private 
    $connection;
        
        
    // this class can and probably should be ignorant of the kind of connection we're using
        // so it expects an existing connection object to be passed to it
        // this is the dependency injection pattern cpradio was talking about
        
    public function __construct(ConnectionInterface $connection)
        {
            
    $this->connection $connection;
        }
        
        
    // ...

    Your viewing my "connections" incorrectly. My process MUST use both.

    So maybe I should rephrase how it works then...

    dur_files utilizes ftp and dur import utliizes mongo, and in order to do use dur_import, it needs the files (fur_files).

  12. #12
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by K. Wolfe View Post
    Your viewing my "connections" incorrectly.
    Indeed. I realized this too late.

    Quote Originally Posted by K. Wolfe View Post
    My process MUST use both.
    "use" is the key word, because dur_import can use dur_files without needing to extend dur_files. Inheritance is unnecessary. Likewise, dur_import can use mongo_conn without needing to extend mongo_conn. (Imagine if all your controllers were required to extend your database just to use the database.) I don't actually think what you're doing requires any inheritance at all.

    PHP Code:
    /**
     * An FTP connection.
     */
    class ftp
    {
        
    // ...
    }

    /**
     * An FTP file manager. (Requires an FTP connection object be passed in.)
     */
    class dur_files
    {
        private 
    $ftp;
        
        public function 
    __construct($ftp)
        {
            
    $this->ftp $ftp;
        }
        
        
    // ...
    }

    /**
     * A Mongo DB connection.
     */
    class mongo_conn
    {
        
    // ...
    }

    /**
     * Import dur files from an FTP source into a Mongo DB.
     * (Requires a dur_files object and a mongo_conn object be passed in.)
     */
    class dur_import
    {
        private 
    $dur_files;
        private 
    $mongo_conn;
        
        public function 
    __construct($dur_files$mongo_conn)
        {
            
    $this->dur_files dur_files;
            
    $this->mongo_conn mongo_conn;
        }
        
        
    // ...
    }

    // Tie it all together and start things running.
    $ftp = new ftp('ftp://yadayada');
    $dur_files = new dur_files($ftp);
    $mongo_conn = new mongo_conn('mongodb://localhost:27017');
    $dur_import = new dur_import($dur_files$mongo_conn);
    $dur_import->doImport(); 
    "First make it work. Then make it better."

  13. #13
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,131
    Mentioned
    152 Post(s)
    Tagged
    0 Thread(s)
    At the risk of sounding a bit arrogant We circled back to what I posted on how I'd lay it out

    Granted, if I felt that a common interface should be used across FTP and MongoDB (still not sold that it should be, although it "could be") there is a bit I'd tweak, but regardless, you would still be primarily looking at composition with dependency injection instead of inheritance.

  14. #14
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,268
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by cpradio View Post
    At the risk of sounding a bit arrogant We circled back to what I posted on how I'd lay it out
    We'll overlook the arrogance since you are 100% correct.
    "First make it work. Then make it better."


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
  •