SitePoint Sponsor

User Tag List

Results 1 to 19 of 19
  1. #1
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    defining class methods in separate files

    Hello everyone,

    I've got a class, plugins, which I would like to assign a great deal of methods to...

    PHP Code:
    class plugins {
     ...
       function 
    plugin1(){
        ...
       }
       function 
    plugin1a(){
        ...
       }
       function 
    plugin2(){
        ...
       }
       function 
    plugin2a(){
        ...
       }

    Now, the PHP manual says: "You can NOT break up a class definition into multiple files."

    I know that there are sometimes clever ways of beating restrictions such as the one above... I would like to place the methods for plugin1 in one file and the methods for plugin2 in another file, etc... This would allow me to write plugins and place them in seperate files for easier organization.

    Can anybody suggest a way to do this, or maybe a different method I should be using?

    Thanks,
    James

  2. #2
    SitePoint Member
    Join Date
    Jun 2005
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    then u should use regular codeing instead of oop;

  3. #3
    SitePoint Wizard Dylan B's Avatar
    Join Date
    Jul 2004
    Location
    NYC
    Posts
    1,150
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think grouping them in a class would organize them the best, or break it up into multiple classes using inheritance.

  4. #4
    Ribbit... Eric.Coleman's Avatar
    Join Date
    Jun 2001
    Location
    In your basement
    Posts
    1,268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    you can use the pecl extension rootkit...
    Eric Coleman
    We're consentratin' on fallin' apart
    We were contenders, now throwin' the fight
    I just wanna believe, I just wanna believe in us

  5. #5
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ekram
    then u should use regular codeing instead of oop;
    Never

    Quote Originally Posted by Dylan B
    I think grouping them in a class would organize them the best, or break it up into multiple classes using inheritance.
    I'm trying to think of a way to make that work... I've posted the code I'm using below so you can see what problems I'm having with that...

    Quote Originally Posted by Eric.Coleman
    you can use the pecl extension rootkit...
    I think you mean classkit, right? I'm not too sure I want to use any extensions. I know that's weird but I really like to use only code that I've written...

    Okay. Before I post the code I've got, I'll explain what I'm doing. I'm working through a template file, that looks something like this:

    Code:
    <$ARCHIVES RANGE='2'$>
    <$CURRENT_DATE FORMAT='%y %m'$>
    <$ENTRY TYPE='SUMMARY' SUMMARY_LENGTH='1000'$>
      <$ENTRY_TITLE$>
      <$ENTRY_MESSAGE$>
      <$CURRENT_DATE$>
    <$/ENTRY$>
    That's a sample. It allows html, etc between the tags... But here's how I'm parsing it:

    PHP Code:
           /* This will move recursively through the template, finding nested values
                and rendering each... 
                When a tag is found (ie: ENTRY), it will call the "print_blogs_".$functionname function... Which processes the plugin... I would like to define these functions in separate files, as each plugin can have more than one function associated with it. I would also like for the program to be able to determine whether or not the plugin exists simply by looking at the code, much the same way it currently determines whether or not the method exists now. */

           /* This is the function that simplifies the process... */
         
    function render_area($area){
             
    $parsed_area $this->parse_area($area);
             
    $this->call_plugins($area$parsed_area);
         }
         
         function 
    parse_area($area){
             
    /* Returns an array from $area, which contains a template (or part of a template),
              * that will be used to call the fuctions required to fill the template properly. */
             
    $prop_start '<$';
             
    $prop_end '$>';
             
    $prop_array = array();
             
    $start_pos 0;
             
    $end_pos 0;
             while(
    '1' == '1'){
                 
    $start_pos stripos($area$prop_start$start_pos);
                 if(
    $start_pos === false){
                         break;
                 }
                 
    $end_element stripos($area$prop_start."/"$start_pos);
                 while(
    $start_pos == $end_element){
                         
    $start_pos stripos($area$prop_start$start_pos 1);
                         if(
    $start_pos === false){
                             break;
                         }

                 }
                 
    $end_pos stripos($area$prop_end$start_pos);
                 
    $property substr($area$start_pos strlen($prop_start), $end_pos $start_pos strlen($prop_end));
                 
    $property str_replace("'"'"'$property);
                 
    $property_explode explode(" "$property);
                 
    $property_name $property_explode[0];
                 
    $prop_array_index count($prop_array);
                 
    $prop_array[$prop_array_index]['name'] = $property_name;
                
    $end_tag stripos($area$prop_start.'/'.$property_name$start_pos 1);
                if(
    $end_tag 0){
                    
    /* There was an ending tag, which means that we should call this function again,
                     * but with the text between the two tags... */
                     
    $prop_contents $this->parse_area(substr($area$end_pos strlen($prop_end), $end_tag $end_pos strlen($prop_start)));
                     
    $prop_array[$prop_array_index]['children_text'] = (substr($area$end_pos strlen($prop_end), $end_tag $end_pos strlen($prop_start)));
                     
    $prop_array[$prop_array_index]['children'] = $prop_contents;
                     
    $prop_array[$prop_array_index]['position']['end'] = $end_tag strlen($prop_start.'/'.$property_name);                 

                     
    $end_pos $end_tag;
                }else{
                    
    $prop_array[$prop_array_index]['position']['end'] = $end_pos;
                    
    $end_pos $end_pos;
                }
                 
    $prop_array[$prop_array_index]['position']['start'] = $start_pos;
                 for(
    $i=1$i<count($property_explode); $i++){
                     
                     
    /* Count through the different property values... Place them in the property array... */
                     
                     
    $temp_name substr($property_explode[$i], 0stripos($property_explode[$i], '='));
                     
    $first_quote stripos($property_explode[$i], '"');
                     
    $second_quote stripos($property_explode[$i], '"'$first_quote 1);
                     
    $temp_value substr($property_explode[$i], $first_quote 1$second_quote $first_quote -1);
                     
    $properties_index = @count($prop_array[$prop_array_index]['properties']);
                     
    $prop_array[$prop_array_index]['properties'][$properties_index]['name'] = $temp_name;
                     
    $prop_array[$prop_array_index]['properties'][$properties_index]['value'] = $temp_value;
                     
                 }

                 
    $request_val '';
                 for(
    $i=0$i<@count($prop_array[$prop_array_index]['properties']); $i++){
                     
                     
    /* Create a string that can be used by parse_str(); */
                     
    $request_val $request_val.'&'.
                                     
    strtolower($prop_array[$prop_array_index]['properties'][$i]['name']).'='.
                                     
    $prop_array[$prop_array_index]['properties'][$i]['value'];
                     
                         
                 }
                 
                 
    $request_val substr($request_val1);
                 
                 
    $prop_array[$prop_array_index]['parse_str'] = $request_val;
                 
    $start_pos $end_pos 3;        
             }
             return(
    $prop_array); 
                  
         }
              
         function 
    call_plugins($area$parsed_area){
            for(
    $i=count($parsed_area)-1$i <> -1$i--){
                    
    $function_name "print_blogs_".strtolower($parsed_area[$i]['name']);
                    if(
    method_exists($this$function_name)){
                        
    $replace_value = @$this->$function_name($parsed_area[$i]['parse_str'],
                                                
    $parsed_area[$i]['children_text']);
                        
    $new_area $this->locational_replace($area,
                                                
    $replace_value,
                                                
    $parsed_area[$i]['position']['start'],
                                                
    $parsed_area[$i]['position']['end']);
                    }else{
                        echo 
    "Plugin: ".$parsed_area[$i]['name']." does not exist.";
                    }
                    
    $area $new_area;
            }         
         }
         
         function 
    locational_replace($haystack$replacement$start$end){
                 
    $first substr($haystack0$start);
                 
    $second substr($haystack$end+2);
                 return (
    $first.$replacement.$second);
         } 
    I know that's a lot to look through and it's not that well commented, but it shouldn't be too hard. This is also very much in-development code, so there are probably many areas that can be programmed better. I'm more interested in getting it to actually work before I fine-tune it.

    Thanks,
    James

  6. #6
    SitePoint Evangelist
    Join Date
    May 2004
    Location
    Germany
    Posts
    550
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jkassemi
    PHP Code:
    class plugins {
     ...
       function 
    plugin1(){
        ...
       }
       function 
    plugin1a(){
        ...
       }
       function 
    plugin2(){
        ...
       }
       function 
    plugin2a(){
        ...
       }

    Your naming there suggests a different way to go (at least for me)

    your functions seem to be candidates for classes (perhaps extending a class called Plugin) with the same api, then you could do sth. like
    PHP Code:
    foreach($plugins as $plugin)
    {
         
    $area $plugin->render_area($area);

    This is of course rather a blind guess. I imaging your plugins doing sth. like replacing bb-tags, converting newlines to <br />, etc...
    Like the markup plugins in serendipity do it.

    What exactly are the plugins supposed to do? For me plugins are not necessarily needed to have an working application, they only improve it, or add new features.

    hth

  7. #7
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm writing my first piece of OSS software, a blog with a few new features... The plugins are supposed to allow developers design something that the user can add to their blog with a template... For instance:

    <$CHAT_ROOM MAXUSERS='25' ALLOW='MEMBERSONLY'$>

    Would call upon the chat_room plugin, which would replace the template call with it's application... I decided to write the entire blog so that it works in this way... There are no features that are not plugins. To get the blog title, for instance, a blog title plugin is written. I've been putting them all in the plugins object, and it's getting extremely long... I really want to be able to put the chat_room plugin in the /plugins/chat_room.php file, and include that file only when the template contains the call for it...

    I've been working with this:

    PHP Code:
    $plugin_file "./plugins/".strtolower($parsed_area[$i]['name'].".php");
    include 
    $plugin_file;
    $object_name "plugin_".strtolower($parsed_area[$i]['name']);
    $plugin_class = new $object_name
    But I'm getting errors that the class name cannot be found. I've even tried just putting global functions in the plugin files, but I can't seem to access them. It's as though "include" isn't including the file...

    Thanks for the help,
    James

  8. #8
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your method names show that this is not good OOP programing. You should set up a base abstract class plugin, then inherit them in your separate class files.

  9. #9
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dbevfat
    Your method names show that this is not good OOP programing. You should set up a base abstract class plugin, then inherit them in your separate class files.
    Heh. I'm fully aware that what I'm doing is probably not good form, but I've been coding with only very basic OOP for quite some time, and never needed anything more advanced... Would you mind giving me some code as an example of how you would do it? I don't understand how I should be calling these new classes...

    Why doesn't the above work?

    Thanks,
    James

  10. #10
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is one way you could do it.

    Plugin is the base class, it is defined abstract (you cannot instantiate it) because it does nothing. It only provides you with the basic class shape that every plugin must obey.
    PHP Code:
    abstract class Plugin
    {
      private 
    $Area;
      
      function 
    Initialize($Area)
      {
        
    $this->Area $this->ParseArea($Area);
      }
      
      abstract function 
    ParseArea($Area);
      abstract function 
    RenderArea();

    Now, every new plugin is stored in a separate file and it is defined as:
    PHP Code:
    class MyFirstPlugin extends Plugin
    {
      function 
    ParseArea($Area)
      {
        
    // do some plugin-specific area parsing
      
    }
      
      function 
    RenderArea()
      {
        
    // render $this->Area
      
    }

    Now that you have this, you have to:
    - decide on the strategy of including the proper plugin file based on you plugin name,
    - verify that the included class is inherited from you base Plugin class,
    - create the plugin object when needed,
    - store the plugin object to a list (array),
    - call the objects' Initialize and Render when necessary.

  11. #11
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dbevfat
    - verify that the included class is inherited from you base Plugin class,
    You only need to do that in statically typed languages, here you could just run it. If someone wants to extend from something else, they just need to remember to put in the two methods and all is cool.

    If you want to do this in a statically typed language, you could replace your abstract class with an interface (it is PHP5 only anyway at the moment). There really isn't a need in a dynamically typed language, it would be quite obvious to the developer when they get "Undefined method RenderArea()" errors that they have messed up.

    Regards,
    Douglas
    Hello World

  12. #12
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dbevfat
    This is one way you could do it.

    Plugin is the base class, it is defined abstract (you cannot instantiate it) because it does nothing. It only provides you with the basic class shape that every plugin must obey.

    ...
    Thanks for the help. I got it close to working, thanks to all of your help. But, one more question... Suppose I want the new class to extend both the abstract class, to give it structure, and another class, that defines a few methods useful to plugin creation... Is it possible for a class to extend on two base classes?

    Thanks,
    James

  13. #13
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by DougBTX
    You only need to do that in statically typed languages, here you could just run it. If someone wants to extend from something else, they just need to remember to put in the two methods and all is cool.

    If you want to do this in a statically typed language, you could replace your abstract class with an interface (it is PHP5 only anyway at the moment). There really isn't a need in a dynamically typed language, it would be quite obvious to the developer when they get "Undefined method RenderArea()" errors that they have messed up.

    Regards,
    Douglas
    Missed your post before I posted... True... The plugin developer will most certainly realize that there was an error before they published it... It might be nice to check for them though. I'll see how much extra work it will take me, and see if I want to release that feature in a future version

    -James

  14. #14
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by jkassemi
    I'll see how much extra work it will take me,
    It is one line of code:

    PHP Code:
    if (!is_subclass_of($plugin'Plugin')) { return false; } 
    Or in PHP5 you could use a type hint + an interface.

    I was objecting to it because using an abstract base class puts artificial constraints on the plugin developer ("you must extend from this class"), not because it would be hard for you to enforce

    Douglas
    Hello World

  15. #15
    SitePoint Guru dbevfat's Avatar
    Join Date
    Dec 2004
    Location
    ljubljana, slovenia
    Posts
    684
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Or instanceof operator in PHP5.

    I think that if you provide outside developers with an entry point to your application, you must restrict it to at least satisfy basic methods, which could also be an interface, not an abstract class. GOF says "program towards interface, not implementation" .

    James: you cannot inherit from 2 classes in PHP, but you can inherit a base class and implement an interface - only in PHP5. Interfaces are similar to abstract classes in the way that they force the class to implement public methods. But interfaces cannot hold variables, so here is a bit of drawback compared to the abstract base class Plugin.

  16. #16
    SitePoint Addict jkassemi's Avatar
    Join Date
    Jan 2005
    Location
    Albuquerque
    Posts
    268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmmm... Amazing how something that seems so complex gets cleared up so quickly. I have to say I learned quite a bit today...

    I got the plug-ins separated, implemented an easy way for users to program them, and learned loads about OOP in PHP... Can't thank you guys enough. I'm going to think a little bit more about how exactly I should restrict (if at all) the plug-in when it comes to implementing the general public methods...

    Thanks everyone,
    James

  17. #17
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You just need to write a one page tutorial on how to create plugins (you should do this anyway) and include example code. Your users can then read the tutorial, and use the sample to make their own plugins.
    Hello World

  18. #18
    Ribbit... Eric.Coleman's Avatar
    Join Date
    Jun 2001
    Location
    In your basement
    Posts
    1,268
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I haven't really been keeping on on this topic, but why develop your own file format... why not use simple plain XML


    - Eric
    Eric Coleman
    We're consentratin' on fallin' apart
    We were contenders, now throwin' the fight
    I just wanna believe, I just wanna believe in us

  19. #19
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Eric.Coleman
    I haven't really been keeping on on this topic, but why develop your own file format... why not use simple plain XML
    Use XML for what? I'm not sure I understand what you mean...
    Hello World


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
  •