Help with OOP class and its members

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

    Help with OOP class and its members

    Hello,

    I have a very small login script that I feel is kind of a mess. I would like to clean it up and do it the correct way. My script is posted below. I would like to have some help in understanding what members, if any I should declare.

    [PHP]class Login
    {
    function Login($account, $operator,$pass word)
    {
    }
    function getUser()
    {
    ob_start();
    if(isset($accou nt) && ($operator) && ($password))
    {
    $password = md5($password);
    require_once("d atabase.php");
    $db = new Database();
    $result = $db->query("");
    $count = $db->count();
    if ($count == 1)
    {
    foreach($result as $key)
    {
    $level = $key['level'];
    $name = $key['last_name'];
    }
    $_SESSION['name'] = $name;
    $_SESSION['user'] = $user;
    $_SESSION['level'] = $level;
    header("locatio n:index.php?id= 6");
    }
    else
    {
    header("locatio n:index.php?id= 1");
    }
    }
    ob_end_flush();
    }
    }[/PHP]
  • Atli
    Recognized Expert Expert
    • Nov 2006
    • 5062

    #2
    I don't know if creating a class solely for login is the right move.
    I would create a class that handles all user interaction, and add a Login method to that class.

    I would also not create a Database object inside the class. I would create it outside it and pass it into the class through the constructor. That way you could just create one database instance and use it wherever it is needed.

    It is probably not a good idea to add the header-redirect into the method itself. That would be best placed outside the class.

    Consider this example:
    (It's a bit long, but it would take much longer to explain this in words :P)
    [code=php]
    <?php
    class User
    {
    /**
    * Members. These will probably not fit your
    * application. They are just for show.
    */
    public $Name;
    private $_role;
    private $_whateverelse;

    private $_dbLink;
    private $_isLoggedIn

    /**
    * Class constructor. Logs the user in automatically if the
    * user info is passed
    */
    public function __construct(Dat abase &$dbLink, $password=null, $name=null)
    {
    // Intialize members
    $this->_dbLink = $dbLink;
    $this->Name = $name;
    $this->_role = "Guest";
    $this->_whatever = "Whatever else data you may need";
    $this->_isLoggedIn = false;

    // Log in the user if the info was passed.
    if($name != null && $password != null) {
    $this->login($passwor d, $name);
    }
    }

    /**
    * Attempts to log the user in.
    *
    * @throws Exception
    */
    public function login($password , $name=null)
    {
    // Use the Name member if no $name was passed in the parameter
    $name = ($name == null ? $this->Name : $name);

    // Check if the parameters have valid values
    if(empty($name) || empty($password )) {
    throw new Exception("Can' t log in. Username or password is empty.", 001);
    }

    // Query for the user info
    $result = $this->_dbLink->query("");
    if(!$result) {
    throw new Exception("Unab le to log in. Database query failed.", 002);
    }

    // Validate the result data
    if($result->getRowCount( ) == 1) {
    // Fetch the row and set the members.
    $dbRow = $result->fetchRow();
    $this->Name = $name;
    $this->_role = $dbRow['UserRole'];
    $this->_isLoggedIn = true;
    }
    else {
    throw new Exception("Unab le to log in. User information is incorrect.", 003);
    }
    }

    /**
    * Read-only properties
    */
    public function isLoggedIn() {
    return $this->_isLoggedIn;
    }
    public function getRole() {
    return $this->_role;
    }
    public function getWhateverElse () {
    return $this->_whateverels e;
    }
    }
    ?>
    [/code]
    Which could be used somewhat like this:
    [code=php]
    <?php
    try {
    // Create a database
    require_once("d atabase.php");
    $dbLink = new Database(...);

    // Create user and login
    $user = new User($dbLink, "MyPassword ", "Username") ;

    // Determing wether the user was successfully logged in.
    if($user->isLoggedIn() ) {
    echo "Welcome {$user->Name}. You have been logged in";
    } else {
    echo "You were not logged in!";
    echo "In fact... seeing as the class throws an exception if the login fails... you should never see this message :P";
    }
    }
    catch(Exception $ex) {
    echo '<strong>An error has occurred:</strong><br />'. $ex->getMessage() };
    }
    ?>
    [/code]
    Edit:
    To understand the parameters in the constructor better, you may want to check out: type hinting and passing by reference

    Comment

    • fjm
      Contributor
      • May 2007
      • 348

      #3
      Wow Atli, sometimes there are no words to describe a post and this is one of them. You are at a much higher level of OOP than I am. I am totally lost now.. :)

      I honestly have no idea what to do with that code. I agree, there is probably a much better way of handling my logins than that script I posted but I am more lost now than I was before. haha...

      I suppose I can play around with the code you posted but I can almost guarentee you that I will hack it up so bad that it won't be worth much afterward.

      All of your help was not in vain tho. I got other bits and pieces of useful information that I can use. I always wondered if using an object within a method was the right way to go and I see that it is not. Also, using header() inside of a method.

      Comment

      • fjm
        Contributor
        • May 2007
        • 348

        #4
        Ok Alti, I am up for the challange. I am going to take the user class and see what I can do with it. I will post back here when I have something useful or when I need some guidance, whichever occurs first :)


        Thanks again!

        Comment

        • Markus
          Recognized Expert Expert
          • Jun 2007
          • 6092

          #5
          I wonder why type hinting with 'int' and 'string' isn't supported?

          Comment

          • fjm
            Contributor
            • May 2007
            • 348

            #6
            Ok Atli,

            What I figured I would do is take the code you provided and firstly create tab indentations so that it becomes more readable to me, which makes it look less dawnting to me. :)

            Then I figured I would take the constructor and its members and focus on just that part. I have included the actual properties/members? in the constructor for you to look at. I also wanted to take this code section by section because I have questions about the way you did a few things that are not clear to me. So, here is the code.

            [PHP]
            public $Account;
            public $Operator;
            private $Password;
            private $_dbLink;
            private $_isLoggedIn

            public function User(Database &$dbLink, $password=null, $name=null)
            {
            $this->_dbLink = $dbLink;
            $this->Account = $name;
            $this->Operator = null;
            $this->Password = null;
            $this->_isLoggedIn = false;

            if($account != null && $operator != null && $password != null)
            {
            $this->login($account , $operator, $name);
            }
            }
            [/PHP]
            My questions are:

            1. What is this? "Database &$dbLink"
            2. What is the amp. sign for? I thought that was only used in php4
            3. I changed __construct to User because I think that __construct was for php4 as well. Right? I mean, either way should be ok, I think.
            4. I noticed that you use "_" to prepend your variables. Is there a reason for this? Just curious. :)
            5. I added "Account", "Operator", "Password" as "Members". Am I correct on this?

            Comment

            • Atli
              Recognized Expert Expert
              • Nov 2006
              • 5062

              #7
              Originally posted by fjm
              My questions are:

              1. What is this? "Database &$dbLink"
              2. What is the amp. sign for? I thought that was only used in php4
              3. I changed __construct to User because I think that __construct was for php4 as well. Right? I mean, either way should be ok, I think.
              4. I noticed that you use "_" to prepend your variables. Is there a reason for this? Just curious. :)
              5. I added "Account", "Operator", "Password" as "Members". Am I correct on this?
              1. The "Database" part is what we call type hinting. It means that the $dbLink parameter must be an object based on the Database class. Anything else will cause an error.

              2. The ampersand means that the $dbLink parameter will be passed by reference.
              That is; rather than making a new copy of the variable and using that in the constructor, PHP passes the memory location of the original object, which will then be used instead.

              3. Actually, __construct was first introduced in PHP5 and it is the preferred method. It just makes it easier to spot the constructor.
              Originally posted by PHP manual
              For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class.
              4. I do that so I can more easily spot what type of member I am using. As you see, I prefix private members and methods with a single _ char.
              I encourage you to find a naming-convention you like and stick with it. It's extremely annoying when there is no rule to how members are named.

              5. I can't see a reason why not. I would still encourage you to pick a naming-convention and stick to it, whether it is the one I use or something else. Your new Password member is a private member, so using my convention it should be named "_password" , and the other two should start with a lowercase letter.

              There are a lot of naming-conventions. I prefer the C# conventions, but the one I am using in the code I showed you is what is usually used with PHP.
              Last edited by Atli; Jun 22 '08, 02:17 AM. Reason: Added the links

              Comment

              • Atli
                Recognized Expert Expert
                • Nov 2006
                • 5062

                #8
                Originally posted by markusn00b
                I wonder why type hinting with 'int' and 'string' isn't supported?
                I don't know. Even with PHP's loosely-typed syntax, these keywords are used for other purposes. I can't see why this should be allowed. The manual doesn't explain this, it just says it isn't supported.

                Maybe this is something that will be fixed in PHP6?

                Edit: Or not. Found this in this bug that was filed about this subject:
                Originally posted by helly
                We will not provide typehints for primitive types as PHP has automatic
                typeconversion for them Also we are not adding any checks for primitive
                types since that would either slow down the compile step or would
                require new keywords.

                Comment

                • pbmods
                  Recognized Expert Expert
                  • Apr 2007
                  • 5821

                  #9
                  Heya, Frank.

                  There's precious little I can add to Atli's comprehensive response, but I figured I'd get my 3¢ in (that's .005% of a stimulus check, you know):

                  Moving from procedural to object-oriented code also requires a shift in the way you look at your project.

                  With procedural code, you tend to think in terms of tasks and processes (e.g., login, logout, createUser, deleteUser and so on).

                  When you make the move to object-oriented code, you need to shift your thinking so that you are building objects that are able to do certain tasks (in this case, as Atli demonstrated, a User object that is able to login and so on).

                  One caveat I might as well point out (it's on the PHP 5 certification exam, by the way):

                  You don't need the ampersand operator when passing objects as parameters; all objects in PHP 5 are automatically passed by reference (this is not the case in PHP 4).

                  Comment

                  • pbmods
                    Recognized Expert Expert
                    • Apr 2007
                    • 5821

                    #10
                    Incidentally, I've never seen the '@throws' tag in the PHPDocumentor manual, nor do I remember it from my recent excursion through its source code.

                    Okay, NOW I'm done.

                    *puts nitpicking needles away*

                    Comment

                    • fjm
                      Contributor
                      • May 2007
                      • 348

                      #11
                      Hey Pbmods :) Long time no see man! I haven't seen you on this forum as much as before. Anyway, cool.. I'm glad your still around.

                      Thanks for the 3 cents. All the advice I get here is truly golden.

                      I have to say that OOP is a royal P A I N in the you know what. I can see that it requires me to think differently about how I need to lay out objects and such. Honestly, Alti is fantastic at what he teaches but I am still a noob when it pertains to OOP and my brain doesn't like it. :) I simply don't understand a lot of what is going on. I thought I understood the basics of OOP but I guess I really don't. "Members and Mutators"?? Good Lord man. :)

                      One good thing about procedural is that you just program.. you go.. With OOP my project has halted to an absolute standstill and I have no idea what to do. I simply do not have the knowledge.

                      I am going to try and sit down and read about some of the things that Alti has tried to help me with and see where that takes me.

                      Comment

                      • fjm
                        Contributor
                        • May 2007
                        • 348

                        #12
                        Originally posted by Atli
                        The "Database" part is what we call type hinting. It means that the $dbLink parameter must be an object based on the Database class. Anything else will cause an error.
                        Ok, thanks for your responses Atli. How would I go about using it? I mean, do I have to create the database object first in the user class? I googled it and am having a hard time understanding this.

                        Thanks for the explanation on the naming conventions. If it is ok with you, I will adopt your. I like it. :)

                        EDIT:
                        I found a terriffic example on passing_by_refe rence on phpBuilder's site. I understand it. It is a very simple concept really. :) The way I see it, I create a db object in my process script and pass it to the constructor of the user class. Am I correct?

                        Also, just for clarification, would I need the word "Database" as it appears in the constructor? (function User(Database &$DBLink.... ..)

                        Would I be ok with just &$DBLink?

                        Comment

                        • Atli
                          Recognized Expert Expert
                          • Nov 2006
                          • 5062

                          #13
                          Originally posted by pbmods
                          One caveat I might as well point out (it's on the PHP 5 certification exam, by the way):

                          You don't need the ampersand operator when passing objects as parameters; all objects in PHP 5 are automatically passed by reference (this is not the case in PHP 4).
                          I was under the impression that objects and variables passed without the ampersand would be passed by reference until they were modified. Then the passed object would receive it's own, separate, memory allocation, independent of the original object.

                          Is that wrong?

                          Edit:
                          Turns out that I am wrong. I just tested it and even without the ampersand, the passed object remains a reference to the original, no matter what I do to it.

                          Nice... that means I can stop adding ampersands all over the place :P

                          Originally posted by pbmods
                          Incidentally, I've never seen the '@throws' tag in the PHPDocumentor manual, nor do I remember it from my recent excursion through its source code.
                          According to what I've read, it isn't supported yet. But I still tested it and found that some of the layouts in the newest build (at the time) did use it tho.
                          So I'm just adding it no matter what the manual says, if only to make my code... forward-compatible (I guess :P).

                          Comment

                          • Atli
                            Recognized Expert Expert
                            • Nov 2006
                            • 5062

                            #14
                            Originally posted by fjm
                            Also, just for clarification, would I need the word "Database" as it appears in the constructor? (function User(Database &$DBLink.... ..)

                            Would I be ok with just &$DBLink?
                            That would work to. You could leave it out and it would work fine.

                            It is only used to make sure the passed variable is a certain type of object.
                            It's a completely optional thing, no need to bother with it if it is getting in your way.

                            Comment

                            • Atli
                              Recognized Expert Expert
                              • Nov 2006
                              • 5062

                              #15
                              Originally posted by fjm
                              I found a terriffic example on passing_by_refe rence on phpBuilder's site. I understand it. It is a very simple concept really. :) The way I see it, I create a db object in my process script and pass it to the constructor of the user class. Am I correct?
                              Yea that's exactly it. But now that pbmods has pointed out the fact that objects are always passed as references, we don't need the ampersand anymore.

                              Sorry, meant to add that to my other post. forgot :P

                              Comment

                              Working...