Classes and variable clairification

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • fjm
    Contributor
    • May 2007
    • 348

    Classes and variable clairification

    Hello,

    Can someone please help me out? I know that using variables in a class script is a good programming practice but that they are also not required. I want to do things the correct way so I figured I would ask.

    For a while I was declaring all of my vars at the top of the script like:
    [PHP]
    var $myvar;
    var $mysecondvar;
    ...
    [/PHP]
    I would leave the () blank in ALL of my methods and just assign the var in the script where I instantiated the object like so:
    [PHP]
    $something = new something();
    $something->myvar = 'dsfsfjlk';
    $something->mysecondvar = 'dafkad';
    [/PHP]

    After looking at a completed script, I am looking at a lot of lines that reference those public vars and now want to know why couldn't I just declare the vars within the parenthesis and NOT declare them as above?

    What is the difference here? I mean, if I have a variable that will be global inside the class, I can see declaring the vars outside of the parenthesis but short of that, it seems to me that I should be placing the vars within the parenthesis. Am I correct?

    Is there a rule about this somewhere I missed?

    Thanks,

    Frank
  • Atli
    Recognized Expert Expert
    • Nov 2006
    • 5062

    #2
    Hi.

    The constructor of a class should always be used to initialize all members belonging to that class. (Unless it is meant to be null, which makes initializing it rather pointless).

    The way you show in your post to initialize you members is not really OOP. It's more like using an array in a procedural code.

    Btw.. if you are using PHP5, your class members should be declared using either the "public", "protected" or "private" keyword, rather then the old "var" keyword.

    If you are using PHP4... upgrade to PHP5! :)

    Comment

    • fjm
      Contributor
      • May 2007
      • 348

      #3
      Hi Atli,


      Are you saying that public vars should only be used for initializing the constructor?

      I'm sorry, I didn't understand what you meant by my example not being OOP.

      I am using PHP 5. :) Thanks for the heads-up on the "public" keyword. I will make those changes.

      Comment

      • Atli
        Recognized Expert Expert
        • Nov 2006
        • 5062

        #4
        All I'm saying is; every class should have a constructor... and that constructor should always initialize all of the class members.
        In PHP, because of the way it handles variables, this may not seem all that important. But in other languages, and in OOP in general, this is essential.

        You example is of course OOP, it's just written in the good-old procedural PHP style.
        OOP is all about automation.

        If you initialize the variables outside the class, as you did in your example, you will have an x amount of extra lines for each instance of the class. If you were to change a variable name or it's initial value, you would have to search the code and change all those lines.

        If you initialize in the constructor, you will only ever have the x amount of lines, no matter how many instances you create. If you change the variable names or values, you will only ever have to do it once, inside the constructor.

        Comment

        • fjm
          Contributor
          • May 2007
          • 348

          #5
          You are absolutely correct Alti and that was exactly what has prompted this post. I found myself adding a variable in a method and found myself having to go back through my script where I instantiated the object and adding another line to that script in all of the places I needed it. That was when I figured I was doing something really wrong. Thank you for that!

          This example: (New example) :)

          [PHP]
          <?php
          class Something
          {
          public $var1;
          public $var2

          function Something()
          {
          $this->var1 = 'ds';
          $this->var2 = 'df';
          $this->doit();
          }
          function doit()
          {
          echo $this->var1;
          echo $this->var2;
          }
          }
          $foo = new Something();
          ?>
          [/PHP]

          Is this correct?

          EDIT:

          I forgot to mention that what I started doing to stop all of the repitition in having to add lines of new variables into my class was to use a seperate script and initialize or "build" my object in there. Like a process script. I can taylor that script and build my object any way I need it. Am I making myself clear or should I provide an example?

          Comment

          • fjm
            Contributor
            • May 2007
            • 348

            #6
            Here is what I am working on right now. This will provide a real world example of my problem.

            I have a database connection script and a configuration file that holds all of the connection data to connect to the database for my site;s CMS.

            I am in the process of creating a login form to take the user to a totally different part of the site once logged in. My configuration script just has the 4 elements needed to connect to the db. Now I am thinking... "Why should I have a second configuration script?" It is just another file laying around and it seems to me that I should be able to find a better way of handling this.

            What I thought would be a good idea would be to remove the "database_n ame" variable from the configuration file and make that a variable in my database connection script.

            Change from this:
            [PHP]class Database
            {
            var $Host;
            var $User;
            var $DB;
            var $Pass;
            var $link_id;
            var $Query;
            var $Row;
            var $Record = array();
            function Database()
            {
            include("config .php");
            $this->Host = $host;
            $this->User = $user;
            $this->DB = $db;
            $this->Pass = $pass;
            $this->Connect();
            $this->SelectDB();
            }[/PHP]

            To this:
            [PHP]class Database
            {
            var $Host;
            var $User;
            var $DB;
            var $Pass;
            var $link_id;
            var $Query;
            var $Row;
            var $Record = array();
            function Database($db) <------------------NEW
            {
            include("config .php");
            $this->Host = $host;
            $this->User = $user;
            $this->DB = $db;
            $this->Pass = $pass;
            $this->Connect();
            $this->SelectDB();
            }[/PHP]

            I would just remove the $db from the configuration file and pass it into the constructor. My question is.. do I leave " var $DB;" intact or remove it? I mean, it will be passed into the constructor so is it needed at the top of the class?

            Comment

            • Atli
              Recognized Expert Expert
              • Nov 2006
              • 5062

              #7
              Your new example looks just like I pictured. Except, to be consistent, I would also add the access keywords ("public", etc..) to the functions.
              Originally posted by fjm
              I would just remove the $db from the configuration file and pass it into the constructor. My question is.. do I leave " var $DB;" intact or remove it? I mean, it will be passed into the constructor so is it needed at the top of the class?
              You will have to declare all members outside the constructor. The constructor is simply a function that is meant to initialize the members, not create them.

              A few thoughts on your code tho.

              Your constructor doesn't initialize all the members. The "link_id", "Query", "Row" and "Record" members are left uninitialized.
              (Although, Record is initialized outside the constructor, which is a bad habit to :P)

              I would question the need to store the database information in the class. Once you have used it to connect, do you really need it anymore?
              Allowing the Connect function to receive these values as parameters would be ideal.

              You include a config file in your constructor. I would do that outside the class.
              Then you could either pass the values into the constructor and have it forward them to the Connect function, or just call the Connect function after the constructor.
              It's always best to build your classes independent of the project, so that they can be used in more then one project without needing to alter them.

              Consider these modifcations to your code:
              [code=php]
              class Database
              {
              private $link_id;
              public $Query;
              public $Row;
              public $Record;

              public function __construct($ho st, $user, $pass, $dbName)
              {
              $this->link_id = null;
              $this->Query = "";
              $this->Row = 0;
              $this->Record = array();
              $this->Connect($hos t, $user, $pass, $dbName);
              }
              }
              [/code]
              The Connect function would have to be rewritten to use the parameters rather than the members it used to use.

              Comment

              • fjm
                Contributor
                • May 2007
                • 348

                #8
                Originally posted by Atli
                Your new example looks just like I pictured. Except, to be consistent, I would also add the access keywords ("public", etc..) to the functions.
                Ok, Alti, I am going to put on my "stupid hat" for a few minutes because I have to understand this. I never really understood why variables could be made either "private" or "public". Can you please explain the advantages to me? My theory is that the entire class is private, away from people seeing what is inside so why the need to make it private? Or, is this referring to making a variable private to some method or something like that?

                Originally posted by Atli
                You will have to declare all members outside the constructor. The constructor is simply a function that is meant to initialize the members, not create them.
                When you say members, do you mean methods? Could you please show an example of "initialize the members"? I thought I was initializing the methods by calling them inside the constructor like $this->something();

                Originally posted by Atli
                Your constructor doesn't initialize all the members. The "link_id", "Query", "Row" and "Record" members are left uninitialized.
                (Although, Record is initialized outside the constructor, which is a bad habit to :P)
                When you say initialize, do you mean to use $this?

                Originally posted by Atli
                I would question the need to store the database information in the class. Once you have used it to connect, do you really need it anymore? Allowing the Connect function to receive these values as parameters would be ideal.
                I agree. I always felt as tho there was a better way to do that. I seem to recall having a major issue at the time with the path or something. I tried to pass the variables into the class but for some reason could not get it to work. I was left with sticking an include statement into the class to get it working. BTW: PHP does some really crazy stuff with the paths and from what I can gather, seems to look for the include path "relative" to where the object is being called. Am I correct on this?

                Originally posted by Atli
                Consider these modifcations to your code:
                [code=php]
                class Database
                {
                private $link_id;
                public $Query;
                public $Row;
                public $Record;
                Again, I don't understand why the link_id should be private and the query, row and record should be public? Could you please explain?

                Thanks for all of the help!

                Comment

                • Atli
                  Recognized Expert Expert
                  • Nov 2006
                  • 5062

                  #9
                  Ok. Sorry about all the confusion.

                  Variables that belong to a class are referred to as Members.
                  Functions, on the other hand, are referred to as Methods.

                  Both members and methods can be defined as either "public", "private" or "protected" .
                  • Public members/methods are accessible everywhere. From within the class as well as outside the class.
                  • Private members/methods are only accessible from within the class. Only methods belonging to the class can access them.
                  • Protected members/methods act exactly like private members/methods. Except that when the class is inherited, the child class can not access private members/methods, but it can access protected members/methods.

                  My theory is that the entire class is private, away from people seeing what is inside so why the need to make it private?
                  In most OOP languages that would be a correct assumption. But in PHP, they have it backwards. Everything is public, unless specified otherwise.

                  This is due to the fact that in the beginning, there was no option to make things private, so everything was public. Now that they have added the access keywords and the ability to make things private, everything defaults to public to ensure backwards compatibility.
                  (Damn backwards compatibility is killing us!)

                  Anyways, here is an example:
                  [code=php]
                  class testClass
                  {
                  public $publicMember;
                  private $_privateMember ;

                  public function __construct() {
                  $this->publicMember = "I am public!";
                  $this->_privateMemb er = "I am private";
                  }

                  public function printPrivate() {
                  echo $this->_privateMember ;
                  }

                  private function _setPrivate($ne w) {
                  $this->_privateMemb er = $new;
                  }

                  public function setBoth($pub, $priv) {
                  $this->publicMember = $pub;
                  $this->_setPrivate($p riv);
                  }
                  }

                  $inst = new testClass();

                  echo $inst->publicMember ; // Will echo "I am public!"
                  echo $inst->_privateMember ; // Will generate access error

                  $inst->printPrivate() ; // Will print "I am private!";

                  $inst->_setPrivate('v alue'); // Will generate access error
                  $inst->setBoth('pub ', 'priv'); // Will set both members
                  [/code]
                  Note that I append a single _ to all private and protected members and methods... It helps keep track of what is what.
                  Last edited by Atli; Jun 21 '08, 03:38 AM. Reason: Fixed the printPrivate method... accidentally printed the wrong member

                  Comment

                  • Atli
                    Recognized Expert Expert
                    • Nov 2006
                    • 5062

                    #10
                    When I say "initialize the members" I simply mean; to give each member (class variable) some value.

                    Methods / functions do not need to be initialized. If you call them in the constructor, they will be called just as if you had called them from outside the class...

                    For example:
                    [code=php]
                    class testClass
                    {
                    private $_member;

                    public function __construct() {
                    // Initialize the member
                    $this->_member = "Some value";

                    // Call the printMember function
                    $this->printMember( );
                    }

                    public function printMember() {
                    echo $this->_member;
                    }
                    }

                    $inst = new testClass();
                    $inst->printMember( );
                    [/code]
                    This will result in "Some value" being printed twice. Once by the constructor and once by the $inst->printMember( ) call.

                    Comment

                    • Atli
                      Recognized Expert Expert
                      • Nov 2006
                      • 5062

                      #11
                      BTW: PHP does some really crazy stuff with the paths and from what I can gather, seems to look for the include path "relative" to where the object is being called. Am I correct on this?
                      PHP will always start looking for relative includes in the include_path...

                      That is, it will search each entry in the include_path, and it will then search relative to the location of the file that is being executed.

                      Note, that if you include a class into /var/www/index.php from /var/www/include/myClass.php, the class will be imported into the scope it was called from, so that any relative includes from within the class will be called from /var/www/.

                      An include will basically just copy/paste the code where the include() call is. So any path called from there will be relative to the file the include was called from, regardless of the included files original location.

                      Comment

                      • fjm
                        Contributor
                        • May 2007
                        • 348

                        #12
                        Originally posted by Atli
                        [code=php]
                        class testClass
                        {
                        public $publicMember;
                        private $_privateMember ;

                        public function __construct() {
                        $this->publicMember = "I am public!";
                        $this->_privateMemb er = "I am private";
                        }

                        public function printPrivate() {
                        echo $this->publicMember ;
                        }

                        private function _setPrivate($ne w) {
                        $this->_privateMemb er = $new;
                        }

                        public function setBoth($pub, $priv) {
                        $this->publicMember = $pub;
                        $this->_setPrivate($p riv);
                        }
                        }

                        $inst = new testClass();

                        $inst->printPrivate() ; // Will print "I am private!";
                        Wouldn't this print "I am public"? I don't see the private.

                        On the bright side, I understand what you mean now about public, private and protected. To recap:

                        A public method is available outside of the class anywhere. A private method is available only within it's method.

                        Is this correct Atli?

                        Comment

                        • fjm
                          Contributor
                          • May 2007
                          • 348

                          #13
                          Originally posted by Atli
                          PHP will always start looking for relative includes in the include_path...

                          That is, it will search each entry in the include_path, and it will then search relative to the location of the file that is being executed.

                          Note, that if you include a class into /var/www/index.php from /var/www/include/myClass.php, the class will be imported into the scope it was called from, so that any relative includes from within the class will be called from /var/www/.

                          An include will basically just copy/paste the code where the include() call is. So any path called from there will be relative to the file the include was called from, regardless of the included files original location.
                          Yes, thank you for the clarification. Many nights of da head-bangin' were going on over this. :)

                          Comment

                          • Atli
                            Recognized Expert Expert
                            • Nov 2006
                            • 5062

                            #14
                            Originally posted by fjm
                            Wouldn't this print "I am public"? I don't see the private.
                            Your absolutely right. Nicely spotted :)
                            I meant to print the private member but printed the wrong one.
                            (Which I intend to fix btw, just to avoid confusion.)

                            Originally posted by fjm
                            A public method is available outside of the class anywhere. A private method is available only within it's method.

                            Is this correct Atli?
                            Almost :)

                            Private members and methods are only accessible by methods within the same class.
                            (keeping in mind that... method=function , member=variable )

                            Comment

                            • fjm
                              Contributor
                              • May 2007
                              • 348

                              #15
                              Originally posted by Atli
                              When I say "initialize the members" I simply mean; to give each member (class variable) some value.
                              Ok, I understand that. I have always heard "members" referred to as "Properties ".
                              Originally posted by Atli
                              Methods / functions do not need to be initialized. If you call them in the constructor, they will be called just as if you had called them from outside the class...
                              Ok, I understand that too. Thanks. :)

                              What about some of these classes I have seen. FPDF for example imports many of its variables into the methods. I have not seen any of that in your examples and am just a little curious as to why. Is it better or more correct to do it one way over the other?

                              Originally posted by Atli
                              This will result in "Some value" being printed twice. Once by the constructor and once by the $inst->printMember( ) call
                              This took me a few hours to understand also. It was mind boggling. :)

                              Comment

                              Working...