Some OOP confusion Object

Databae.class.php →

<?php 
/**
 * Database class
 * 
 */

class Database {
  private static $_db; //singleton connection object
  private function __construct() {} //Disallow creating a new object of the class with new Database

  private function __clone() {} //disallow cloning the class

  /**
    * Get the instance of the PDO connection
    * 
    * @return DB PDO connection
    */ 

  public static function getInstance() {
    if(static::$_db === NULL) {
      $dsn = 'mysql:host=' . Config::DB_HOST . ';dbname=' . Config::DB_NAME . ';charset=utf8';
      static::$_db = new PDO($dsn, Config::DB_USER, Config::DB_PASS);

      //Raise exceptions when a database exception occurs
      static::$_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    }
    return static::$_db;
  }
}

User.class.php →

<?php
 
/**
 * User class
 */

class User
{
  public $errors;

  /**
   * Signup a new user
   *
   * @param array $data  POST data
   * @return User
   */
  public static function signup($data)
  {
    // Create a new user model and set the attributes
    $user = new static();
    $user->name = $data['name'];
    $user->email = $data['email'];
    $user->password = $data['password'];

    if ($user->isValid()) {
      try {
        $db = Database::getInstance();
        $stmt = $db->prepare('INSERT INTO users (name, email, password) VALUES (:name, :email, :password)');
        $stmt->bindParam(':name', $user->name);
        $stmt->bindParam(':email', $user->email);
        $stmt->bindParam(':password', Hash::make($user->password));
        $stmt->execute();

      } catch(PDOException $exception) {
        // Log the exception message
        error_log($exception->getMessage());
      }
    }
    return $user;
  }


  /**
   * See if an user record already exists with the specified email address
   *
   * @param string $email  email address
   * @return boolean
   */
  public function emailExists($email) {
    try {
      $db = Database::getInstance();
      $stmt = $db->prepare('SELECT COUNT(*) FROM users WHERE email = :email LIMIT 1');
      $stmt->execute([':email' => $this->email]);
      $rowCount = $stmt->fetchColumn(); 
      return $rowCount == 1;
    } catch(PDOException $exception) {
      error_log($exception->getMessage());
      return false;
    }
  }


  /**
   * Validate the properties and set $this->errors if any are invalid
   *
   * @return boolean  true if valid, false otherwise
   */
  public function isValid()
  {
    $this->errors = [];

    // 
    // name
    //
    if ($this->name == '') {
      $this->errors['name'] = 'Please enter a valid name';
    }

    // 
    // email address
    //
    if (filter_var($this->email, FILTER_VALIDATE_EMAIL) === false) {
      $this->errors['email'] = 'Please enter a valid email address';
    }

    if ($this->emailExists($this->email)) {
      $this->errors['email'] = 'That email address is already taken';
    }
    // 
    // password
    //
    if (strlen($this->password) < 5) {
      $this->errors['password'] = 'Please enter a longer password';
    }
    return empty($this->errors);
  }

}

User.class.php →

<?php
 
/**
 * User class
 */

class User
{
  public $errors;

  /**
   * Signup a new user
   *
   * @param array $data  POST data
   * @return User
   */
  public static function signup($data)
  {
    // Create a new user model and set the attributes
    $user = new static();
    $user->name = $data['name'];
    $user->email = $data['email'];
    $user->password = $data['password'];

    if ($user->isValid()) {
      try {
        $db = Database::getInstance();
        $stmt = $db->prepare('INSERT INTO users (name, email, password) VALUES (:name, :email, :password)');
        $stmt->bindParam(':name', $user->name);
        $stmt->bindParam(':email', $user->email);
        $stmt->bindParam(':password', Hash::make($user->password));
        $stmt->execute();

      } catch(PDOException $exception) {
        // Log the exception message
        error_log($exception->getMessage());
      }
    }
    return $user;
  }


  /**
   * See if an user record already exists with the specified email address
   *
   * @param string $email  email address
   * @return boolean
   */
  public function emailExists($email) {
    try {
      $db = Database::getInstance();
      $stmt = $db->prepare('SELECT COUNT(*) FROM users WHERE email = :email LIMIT 1');
      $stmt->execute([':email' => $this->email]);
      $rowCount = $stmt->fetchColumn(); 
      return $rowCount == 1;
    } catch(PDOException $exception) {
      error_log($exception->getMessage());
      return false;
    }
  }


  /**
   * Validate the properties and set $this->errors if any are invalid
   *
   * @return boolean  true if valid, false otherwise
   */
  public function isValid()
  {
    $this->errors = [];

    // 
    // name
    //
    if ($this->name == '') {
      $this->errors['name'] = 'Please enter a valid name';
    }

    // 
    // email address
    //
    if (filter_var($this->email, FILTER_VALIDATE_EMAIL) === false) {
      $this->errors['email'] = 'Please enter a valid email address';
    }

    if ($this->emailExists($this->email)) {
      $this->errors['email'] = 'That email address is already taken';
    }
    // 
    // password
    //
    if (strlen($this->password) < 5) {
      $this->errors['password'] = 'Please enter a longer password';
    }
    return empty($this->errors);
  }

}

$user = new static();

The above static should be class(That’s what I know that class can be instantiated as an object), but this seems to be instantiating a property _db?
Can a property be instantiated just like a class?

static lass is not defined anywhere?

static defines class of current instance. That means either User or some class that extends User.

And… I would to say, your code has a structure problems. But this is out of your question.

1 Like

I didnt get it? Please bear with me. I have hard time understanding this.
Something related to this →

Is it something that is in PHP OOP? If yes, than I have information and learning GAP.

A-a… I understand the problem.

static as method or property modificator means method or property of class, not class instance (object). E.g…

class Foo
{
    private static $p;
}

But static instead of class means exactly that I said above…

$obj = new static();
var_dump($obj instanceof static);  // true
1 Like

I personally just have a simple Database Class

<?php


namespace Miniature;

use PDO;
class Database {

    private $_connection;
    // Store the single instance.
    private static $_instance;

    // Get an instance of the Database.
    // @return Database:
    protected static function getInstance(): Database
    {
        if (!self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public static function pdo(): PDO
    {
        $db = static::getInstance();
        return $db->getConnection();
    }

    // Constructor - Build the PDO Connection:
    public function __construct() {
        $db_options = array(
            /* important! use actual prepared statements (default: emulate prepared statements) */
            PDO::ATTR_EMULATE_PREPARES => false
            /* throw exceptions on errors (default: stay silent) */
        , PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
            /* fetch associative arrays (default: mixed arrays)    */
        , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        );
        $this->_connection = new PDO('mysql:host=' . DATABASE_HOST . ';dbname=' . DATABASE_NAME . ';charset=utf8', DATABASE_USERNAME, DATABASE_PASSWORD, $db_options);
    }

    // Empty clone magic method to prevent duplication:
    private function __clone() {

    }

    // Get the PDO connection:
    protected function getConnection(): PDO
    {
        return $this->_connection;
    }

}

Then in my other classes I do something like the following code snippet:

    public static function page($perPage, $offset): array
    {
        $sql = 'SELECT * FROM ' . static::$table . ' ORDER BY date_updated DESC LIMIT :perPage OFFSET :blogOffset';
        $stmt = Database::pdo()->prepare($sql); // Prepare the query:
        $stmt->execute(['perPage' => $perPage, 'blogOffset' => $offset]); // Execute the query with the supplied data:
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

@codeispoetry,

Please supply a link from where the source code was copied and pasted.

Edit:

I tried the supplied script and got the following errors:


Fatal error:  Uncaught Error: Class 'Config' not found in /var/www/AATEST/codeispoetry/db-stuff/Database.class.php:31
Stack trace:
#0 /var/www/AATEST/codeispoetry/db-stuff/User.class.php(64): Database::getInstance()
#1 /var/www/AATEST/codeispoetry/db-stuff/User.class.php(100): User->emailExists()
#2 /var/www/AATEST/codeispoetry/db-stuff/User.class.php(37): User->isValid()
#3 /var/www/AATEST/codeispoetry/db-stuff/index-001.php(19): User::signup()
#4 {main}
  thrown in /var/www/AATEST/codeispoetry/db-stuff/Database.class.php on line 31

This is a paid course at Udemy.

The author is also a very established Author.

I was struggling with the concept so I requested the author’s opinion last night and at the same time posted it here for further discussion. this is what the author state →

using the static keyword in this context simply refers to the current class that it’s in. So in this case, the User class. It’s a way of creating an object inside a class without referring to the current class name. One reason to do this is to do with inheritance - if you have a subclass of the class User, for example, this would have a different name, so referring to the User class directly might not work. If you use static as we do on the course, it will always refer to the class that it’s in. More details here.

What does this means when we say?
$X = new static()
we are instantiating the same class as an object with the same class?

I could not fully interpret waht is written on that stackoverflow posts.

I would be tempted to pursue the author to simplify your queries. No doubt if you are having problems then others will also be struggling and perhaps the course could get revised.

1 Like

Thanks for replying.

How? Will you join the course?

Did you understand the authors explanation?

According to the PM you sent a basic knowledge of PHP Classes is mandatory. If you think their course requires an in-depth and deeper knowledge then ask the author to explain in further detail.

I will not pay for the Udemy course because PHP validation is a basic requirement and there are many free online tutorials available.