Best OOP design pattern for static class DbTable - php

I have class DbTable, which implements all db queries to database such as insertRecord, updateRecord, ... But variable is not rewriting.
abstract class DbTable {
public static $table;
public static function insertRecord($data) {
// here I add some values to data, but that's not important
my_db::insert(self::$table, $data);
}
}
class User extends DbTable {
public static $table = 'table_users';
}
// everywhere I can call
User::insertRecord($data);
I know I can call
$c = get_called_class();
my_db::insert($c::$table, $data);
but I think that's not best solution at all.
Method and variables can be non static, I just use them because it is comfortable to write User::insertRecord instead of $user = new User(); $user->insertRecord($data);

When you're working with static classes you need to specify your variable source, in this case you're scoping to both classes and not on single class, this makes a difference, because self is scoping to concurrent class and when you want to scope for both classes you have to use static.
/**
* For testing
*/
class my_db {
public static function insert($table, $data){
echo $table;
}
}
abstract class DbTable {
public static $table = null;
public static function insertRecord($data) {
//self::$table is empty
//static::$table has 'table_users'
// here I add some values to data, but that's not important
my_db::insert(static::$table, $data);
}
}
class User extends DbTable {
public static $table = 'table_users';
}
// everywhere I can call
User::insertRecord(['Hi']);
self::$table is empty
static::$table has 'table_users'
You can read more about this here: SO Answer and PHP Documentation

Use static variables are unnecessary in this case. You just need dynamically create User object and them call method.
abstract class DbTable
{
protected $tableName;
public static function insertRecord($data)
{
$object = static::newInstance();
$object->insert($data);
}
public static function newInstance()
{
$className = get_called_class();
return new $className();
}
public function insert($data)
{
my_db::insert($this->tableName, $data);
}
}
class User extends DbTable
{
public function __construct()
{
$this->tableName = 'table_users';
}
}
You can now call:
User::insertRecord(['col1' => 'val1']);
But also you can insert rows from instated object:
$user = new User();
$user->insert(['col1' => 'val1']);

Related

Access Static define table property

I'm really bad at OOP and I can't work out this inherited code I've been given.
This is part of the generic Model class;
abstract class Model
{
protected static $_tableName = false;
protected static $_itemName = false;
public static function tableName()
{
return static::$_tableName;
}
public static function itemName()
{
return static::$_itemName;
}
How do I set the tablename in the Class that I have created???;
class Payments extends Model {
//public $_tableName;
public function __construct()
{
$this->$_tableName = 'payments'; //line 13
}
}
I get an error Undefined variable: _tableName in /var/www/html/lib/Local/Models/Payments.php on line 13 when I don't set it as a parameter. and an error Cannot redeclare static XXX\Model::$_tableName when I do.
UPDATE
When I try to use the find method with this abstract Model, it's not setting the tableName;
public static function find($idOrWhere = false, $params = array(), $limit = false)
{
$sql = "SELECT * FROM " . static::tableName();
I don't know how to set that now. It just ignores what I have put in my class.
You have to remove the $ when accessing a class property:
class Payments extends Model
{
public function __construct()
{
$this->_tableName = 'payments';
}
}
Indeed this is irritating, but that's the way php syntax works.
With static class you need to use the self keyword to initialize property in class:
class Foo {
static $bar;
}
Foo::$bar = array(…);
or
class Foo {
private static $bar;
static function init()
{
self::$bar = array(…);
}
}
Foo::init();

How do I set and use a protected static property?

Here is an abstract class I have to use;
abstract class Model
{
protected static $_tableName = false;
public static function tableName()
{
return static::$_tableName;
}
public static function find($idOrWhere = false, $params = array(), $limit = false)
{
$sql = "SELECT * FROM " . static::tableName();
I can't seem to set the _tableName, static::tableName(), or tableName() in my own class;
class Payments extends Model {
public function __construct()
{
$this->_tableName = 'payments';
}
That's not doing anything! It's not set the tableName to payments. And I can't figure out how to use the method tableName() either.
You are trying to access _tableName in a non-static way (I.e. $this->_tablename) even though you've declared it as static.
You need to access it like so:
self::$_tableName
OR, for late static binding:
static::$_tableName
Overall, you should avoid the use of static classes as much as possible, mainly due to testing purposes.
Static members have to be accessed on the class, not on an instance:
class Payments extends Model {
public function __construct()
{
Payments::$_tableName = 'payments';
}
}
A property declared as static cannot be accessed with an instantiated class object (though a static method can).
Static properties cannot be accessed through the object using the arrow operator ->.
http://php.net/manual/en/language.oop5.static.php
Like any other PHP static variable, static properties may only be initialized using a literal or constant; expressions are not allowed.
According to this material your classes should be reworked that way.
abstract class Model
{
protected static $_tableName = false;
public static function find($idOrWhere = false, $params = array(), $limit = false)
{
$sql = "SELECT * FROM " . self::tableName();
...
}
private static function tableName()
{
if (!static::$_tableName) {
throw new \RuntimeException('No table name provided');
}
return static::$_tableName;
}
class Payments extends Model {
protected static $_tableName = 'payments';
}
Btw, __contruct is called on object instantiation and you should not set any static properties values there.

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();
}
}

How to override a static property of a parent object and let the parent object access the new value in PHP?

This is what I have: All objects that can be persisted on the database extend the DatabaseObject abstract class, which has all the logic code to actually watch for attribute changes and run the databas queries.
I'm using two static variables to define object-specific details. I define them generically in the base class, and then supposedly I overwrite them in the actual database objects.
The problem is: When the code in the parent class is actually executed, it uses the old parent value instead of the current object value.
Here's the code for the base class:
abstract class DatabaseObject {
public $id;
private static $databaseTable = NULL;
private static $databaseFields = array();
private $data = array();
private $changedFields = array();
public function IDatabaseObject($id) {
$this->id = $id;
$this->data = Database::GetSingle(self::$databaseTable, $id);
Utils::copyToObject($this, $this->data, self::$databaseFields);
}
public static function Load($id) {
return new self($userID);
}
public static function Create($data) {
$id = Database::Insert(self::$databaseTable, $data);
return new self($id);
}
public function Save() {
$data = Utils::copyFromObject($this, $this->changedFields);
Database::Update(self::$databaseTable, $data, $this->id);
}
public function __constructor() {
// We do this to allow __get and __set to be called on public vars
foreach(self::$databaseFields as $field) {
unset($this->$field);
}
}
public function __get($variableName) {
return $this->$variableName;
}
public function __set($variableName, $variableValue) {
// We only want to update what has been changed
if(!in_array($variableName, $this->changedFields) && in_array($variableName, self::$databaseFields)) {
array_push($this->changedFields, $variableName);
}
$this->$variableName = $variableValue;
}
}
And here's the code for one of the objects extending the base class above:
class Client extends DatabaseObject {
public static $databaseTable = "clients";
public static $databaseFields = array("name","contactName","primaryUserID","email","is_active","rg","cpf","cnpj","ie","addrType","addrName","addrNumber","addrComplement","addrPostalCode","addrNeighborhood","addrCity","addrState","addrCountry","phoneLandline","phoneFax","phoneMobile");
public $name;
public $contactName;
public $primaryUserID;
public $email;
public $is_active;
public $rg;
public $cpf;
public $cnpj;
public $ie;
public $addrType;
public $addrName;
public $addrNumber;
public $addrComplement;
public $addrPostalCode;
public $addrNeighborhood;
public $addrCity;
public $addrState;
public $addrCountry;
public $phoneLandline;
public $phoneFax;
public $phoneMobile;
public static function Load($id) {
return new Client($id);
}
}
What am I doing wrong here? Is there another way I can achieve the same result?
A brief addendum: I declare the attributes in the class body mainly to let it be seen by the NetBeans' auto-complete feature.
You are looking for Late Static Binding.
So you need to use:
static::$databaseTable
instead of
self::$databaseTable
This feature is available as of PHP 5.3. Simulating this in PHP 5.2 is very hard, because of two reasons: get_called_class is available only since PHP 5.3, too. Therefore it must be simulated, too, using debug_backtrace. The second problem is, that if you have the called class, you still may not use $calledClass::$property because this is a PHP 5.3 feature, too. Here you need to use eval or Reflection. So I do hope that you have PHP 5.3 ;)

OO PHP where to reference singleton class?

I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!

Categories