How to get data from parent class (not extend) - php

Here is sample code:
namespace myApp
class app
{
private $pdo = null;
public function __construct() {
$this->user=new User();
$this->user->getPDO();
}
}
class User
{
public function getPDO() {
//get PDO from app class
}
}
How from User class get $pdo from app class??
Can't use extends because of construct in app class.
I don't want to declare independent classes (app and User) and than use global to communicate with each other.
EDIT:
is this solution ok?
namespace myApp
class app
{
public $pdo = null;
public function __construct() {
$this->user=new User($this);
$this->user->getPDO();
}
}
class User
{
private $app=null;
public function __construct($app) {
$this->app=$app;
}
public function getPDO() {
return $this->app->pdo;
}
}

This sounds like a good candidate for dependency injection.
You can declare the constructor for your Userclass for example like
__constuct($pdo) {
$this->pdo = $pdo;
}
And then create User like
$this->user = new User($this->pdo)
An added advantage of this is that when you want to test your code you can easily mock pdo and test user without doing actual database actions.

You have to declare 2 functions in your app class like this:
Then you have acces through this functions to the pdo variable
public function setPDO($pdo) {
$this->pdo = $pdo;
}
public function getPDO() {
return $this->pdo;
}

Related

Type hinting an array key of a function argument

Let's say I have a class that takes in an array:
class Database {
function __construct($options = ['pdo' => '' ]) {
$this->pdo = $options['pdo'];
}
}
Is there a way to specify class for the array key? Maybe something like this?
class Database {
function __construct($options = [\PDO 'pdo']) {
$this->pdo = $options['pdo'];
}
}
Actually it is not possible to type hint array keys with PHP. There are some possible solutions to this, but none of them will work with type hints on arrays.
Validating the options in the constructor
Since it is not possible to check the array keys for a specific type hint you can check with an if condition, if a specific option isset and if it is an instance of PDO.
class Database
{
protected PDO $pdo;
function __construct(array $options)
{
if (!isset($options['pdo']) || !$options['pdo'] instanceof PDO) {
// error handling here
}
$this->pdo = $options['pdo'];
}
}
Using an interface
The use of an interface is obvious here. Others, like e.g. Doctrine ORM or Laminas, use an aware interface to point out, that there is an instance of a specific class available.
interface PdoAwareInterface
{
public function getPdo(): PDO;
public function setPdo(PDO $pdo): void;
}
class Database implements PdoAwareInterface
{
protected PDO $pdo;
public function __construct(array $options = [])
{
...
}
public function getPdo(): PDO
{
return $this->pdo;
}
public function setPdo(PDO $pdo): void
{
$this->pdo = $pdo;
}
}
class DatabaseFactory
{
public function __invoke()
{
$pdo = new PDO(...);
$database = new Database([]);
$database->setPdo($pdo);
return $database;
}
}
As you can see the PDOAwareInterface is implemented. It points out, that a PDO instance is aware. You can use it e.g. in a factory, to set the pdo instance via the interface implemented methods.
Options Interface
Using in interface for the options itself is a bit messy, because here you cannot be sure whether the PDO instance was actually set before intializing the Database class. Anyway ... it could be a possible way.
interface DatabaseOptionsInterface
{
public function getPdo(): PDO;
}
class DatabaseOptions implements DatabaseOptionsInterface
{
protected PDO $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function getPdo(): PDO
{
return $this->pdo;
}
}
class Database
{
protected PDO $pdo;
public function __construct(DatabaseOptionsInterface $options)
{
$this->pdo = $options->getPdo();
}
}
class DatabaseFactory
{
public function __invoke()
{
$pdo = new PDO(...);
$options = new DatabaseOptions($pdo);
$database = new Database($options);
return $database;
}
}
Basically like initialisation with an AwareInterface, but via an additional DatabaseOptions instance.
Conclusion
Personally, I tend towards awareness, because here I can always check whether the object holds a certain instance ready. This would only be possible in a roundabout way via an options class, for example.
PHP does not have strongly typed arrays.
What you can do instead is use a class or interface to represent the $options parameter
interface Options {
public function pdo(): \PDO;
}
class Database {
private \PDO $pdo;
function __construct(Options $options) {
$this->pdo = $options->pdo();
}
}

Instantiate class dependencies with static method

I want to use a static method of an example class without instantiating class. This method uses a dependencie class and is instantiated with __construct method. How can this dependency class be instantiated. Example:
class user {
protected static $db;
public function __construct() {
self::$db = database::getInstance();
}
public static function get_user() {
$user = self::$db->query("sql");
return $user;
}
}
I know the solution with autoloader or I could just add self::$db = database::getInstance(); in every static method.
Could someone kindly show me better suggestions?
You can add a static setter and getter for the db object and throw an exception if someone tries to access the getter without calling the setter first:
class User
{
protected static $db;
public static function setDB($db)
{
self::$db = $db;
}
protected static function getDB()
{
if (!self::$db) {
throw new Exception('You must `setDB()` the db object before attempting to get it.');
}
return self::$db;
}
public static function getUser()
{
return self::getDB()->query('sql');
}
}
User::setDB(database::getInstance());
User::getUser();

php enforce type of extending class

Is there any way in php to make sure that a class can be extended by one and only one class?
I have some code that illustrates what I'm trying to do, basically I have a DB manager class and a DB query class that is extended by the manager class. What I'd like to do is make sure that the DB query class can only be used by the DB manager class.
The code below works, but it seems very rough. In the code I delcare the query class abstract with a single abstract function that checks the classname, or I could simply declare all of the Manager functions as abstract in the query class (which seems hacky). If there is a simpler way to do this than my code below that would be very useful...
abstract class DB_Query {
private static $HOST = 'localhost';
private static $USERNAME = 'guest';
private static $PASSWORD = 'password';
private static $DATABASE = 'APP';
//////////
/* USING ABSTRACT FUNCTION HERE TO ENFORCE CHILD TYPE */
abstract function isDB();
/* OR USING ALTERNATE ABSTRACT TO ENFORE CHILD TYPE */
abstract function connect();
abstract function findConnection();
abstract function getParamArray();
//////////
private function __construct() { return $this->Connect(); }
public function Read($sql) { //implementation here }
public function Query($sql) { //implementation here }
public function Fetch($res, $type='row', $single='true') { //implementation here }
}
class DB extends DB_Query {
public $connections = array();
public static $instance;
public function isDB() {
if (get_parent_class() === 'Database' && get_class($this)!=='DB') {
throw new \Exception('This class can\'t extend the Database class');
}
}
public function connect($host=null,$user=null,$pass=null,$db=null) { //implementation here }
function findConnection($user, $password=null) { //implementation here }
public function getParamArray($param) {}
public function threadList() {}
public function getThread($threadId=null) {}
public static function Singleton() { //implementation here }
private function __construct() { //implementation here }
}
I would go after marking the constructor of DB_Query as final and implementing it the way that it checks the instance and fires some exception. Something like this
class Base {
final function __construct() {
if (!$this instanceof Base && !$this instanceof TheChosenOne) {
throw new RuntimeException("Only TheChosenOne can inherit Base");
}
/**
* use this function as constructor
*/
$this->__internal_base_construct();
}
protected function __internal_base_construct() {
// constructor code
}
}
But your problem is rather strange and kind of breaking the idea of OOP in several ways. Just combine it into a single class and use final class directive.
http://php.net/manual/en/language.oop5.final.php
class Database_Query extends Database {
public static $instance;
public function Query($sql) {}
public function Fetch($res, $type='row', $single='true') {}
public static function Singleton() {}
private function __construct() {
$this->link = $this->connect()->find('guest')->getLink();
}
}

Classes using mysqli

I am building an API in PHP and I have a question. I'm using classes, and some of these classes need to access my database. However, I don't want to define variables for the database in every single class in order to open it, or have to send my mysqli object as a parameter of every single class constructor.
What would be the best way to go about this? Do I define a global variable of some kind?
A classic solution would be as follows
Create an instance of dbatabase handler class, either raw mysqli (worse) or better abstraction class (way better)
In the constructor of your application class take this db class instance as a parameter and assign it to a local variable
Use this variable with your class.
A quick example:
class Foo()
{
protected $db;
function __construct($db);
{
$this->db = $db;
}
function getBar($id)
{
return $this->db->getOne("SELECT * FROM bar WHERE id=?i", $id);
}
}
$db = new safeMysql();
$foo = new Foo($db);
$bar = $foo->getBar($_GET['id']);
How about using a static classes?
class mysqli_wrapper {
private static $db = null;
public static function open() {
GLOBAL $opts; // this can be global or setup in other ways
if (!self::$db) {
self::close();
self::$db = null;
}
self::$db = #mysqli_connect('p:'.$opts['hn'], $opts['un'], $opts['pw'], $opts['db']);
return self::$db;
}
public static function query($qry) {
return mysqli_query ( self::$db, $qry );
}
public static function affected_rows() { return #mysqli_affected_rows(self::$db); }
public static function error() { return #mysqli_error(self::$db); }
public static function close() { #mysqli_close(self::$db); }
} // end mysqli_wrapper
mysqli_wrapper::open(); // Here's how to call it
In a system I maintain my app needs to access its own MySQL db, as well as remote Oracle and SQL Server databases, and I use a trait for it. Here's a simplification of my code, just using MySQL:
dbaccess.php
trait DatabaseAccess {
protected $db;
private $host = 'host', $dbName = 'db', $username = 'username', $password = 'pword';
public function connectToMysql() {
$this->db= new mysqli(......);
}
}
then in myclass.php
require 'dbaccess.php';
class MyClass {
use DatabaseAccess;
//class code.....
}
All elements of DatabaseAccess will be available as if you hand-typed them in MyClass.
Note: if you're using PHP < 5.4, then this solution won't be possible.

How do I access parent property from subclass? PHP

I have an issue accessing top level variables from sub-level class.
Here's an example...
Application.php:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database;
}
}
Configuration.php:
class Configuration {
var $dbhost = 'localhost';
}
Database.php:
class Database {
function __construct() {
echo parent::config->dbhost;
}
}
It is clear to me that usage of parent is wrong here as the subclass does not extend the parent class, but how do I access it?
Thank you.
You should create a Base class that in its construct creates a $db link. Then let all classes that require database access extend that class. Your nomenclature here with "parent class" is incorrect.
class Base {
private $db; // Make it read-only
function __construct() {
$this->db = DB::connect(); // It's a good practice making this method static
}
function __get($property) {
return $this->$property;
}
}
class Application {
public $config;
function __construct() {
parent::__construct();
require_once 'Configuration.php';
require_once 'Database.php';
$this->config = new Configuration();
}
function random_function() {
$this->db(....) // Has full access to the $db link
}
}
The parent notation is used to access the parent of the object in the object hierarchy. What you are doing here is trying to get at the caller, not the parent
The way that you would do this is to pass in an instance of your configuration to the database object.
class Database {
protected $config;
public function __construct(Configuration $config){
$this->config = $config;
}
public function connect(){
//use properties like $this->config->username to establish your connection.
}
}
The parent notation is used when you extend a class and make a child class to call methods on the parent .
class MySuperCoolDatabase extends Database {
protected $is_awesome;
public function __construct(Configuration $config){
// do all the normal database config stuff
parent::__construct($config);
// make it awesome
$this->is_awesome = true;
}
}
This defines a child class, which is a type definition that serves the same role as the base class with a slightly different implementation. Instances of this can still be said to be a Database.... just a different kinds of database.
Well, although I think that Orangepills answer is better. If you dont want to use it and since all variables are public, you could simply pass the variable like this:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database($this->config->dbhost);
}
}
class Configuration {
var $dbhost = 'localhost';
}
class Database {
function __construct($dbhost) {
echo $dbhost;
}
}

Categories