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.
Related
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();
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']);
In my model, I am extending Zend_Db_Table_Abstract. Inside, I have a protected $_name = 'table_name'.
Now, if I define a constructor, and a private variable private $_var and define it inside the constructor, the model does not work anymore! When I call $this->createRow() or anything, nothing happens! Why is this constructor doing this?!
This is what I have:
<?php
class myClass extends Zend_Db_Table_Abstract
{
protected $_name = 'table_name';
private $_var;
public function __construct($var)
{
$this->_var = $var;
}
public function getById($id)
{
$select = $this->select()->where('id =?',$id);
return $this->fetchRow($select);
}
}
This doesn't work! If I remove the __construct(), and the private variable, then it works! Why?
Thanks
If you override the constructor of Zend_Db_Table_Abstract, you should probably call the parent constructor:
class MyClass extends Zend_Db_Table_Abstract
{
protected $_name = 'table_name';
private $_var;
public function __construct($var)
{
$this->_var = $var;
parent::__construct(); // add this
}
// the rest...
}
The parent constructor calls some protected methods _setup() (which in turn calls _setupDatabaseAdapter() and _setupTableName()) and init() (which is empty in the parent, but you can use to add some processing to the final step of object instantiation).
you have to be more clear when asking questions. write code if you have to.. No one can determine whats wrong with your application with only 2 piece of information.. with that said..
first yo should define your variable outside constructor and initialize inside the constructor if you have to.
Your model will not magically know that a db abstract class exist which connects to your database. you will have to create an object inside the model constructor.
here is the code
// DB Abstract class
class Application_Model_DbTable_myTable extends Zend_Db_Table_Abstract
{
protected $_name = 'myTable';
}
// Your model class
class Application_Model_myModel {
private $_var;
public function __construct() {
$this->_var = new Application_Model_DbTable_myTable();
}
}
Hope this was what you were looking for.. and only thing I understood from your question.
dins
It has been implied in other answers but not stated... You class failed because you overrode the constructor and didn't call the parent constructor so the object did not get created properly.
Normally when these classes are constructed, they are constructed through setOptions() which takes an array in constructor. So if you really have to override the constructor you might try something like:
public function __construct($var, $config = array())
{
$this->_var = $var;
parent::__construct($config);
}
now you should be able to set your variable and pass any configuration values you need to pass.
However it would be best to avoid the constructor and use the supplied init() method if at all possible.
<?php
class myClass extends Zend_Db_Table_Abstract
{
protected $_name = 'table_name';
private $_var;
public function init()
{
$this->_var = $var;
}
public function getById($id)
{
$select = $this->select()->where('id =?',$id);
return $this->fetchRow($select);
}
}
I have two static values: "type" and "typeID". Type is human readable and constant, and typeID needs to be looked up from the database, based on the value of type. I need the lookup to happen once, when the class definition is first loaded
To illustrate, here is some code that doesn't work because you can't call functions in the declaration space.
MyClass extends BaseClass {
protected static $type = "communities";
protected static $typeID = MyClass::lookupTypeID(self::$type);
}
Is there a magic method that is called exactly once when the class definition is loaded? If there is something obvious I'm missing it.
shamelessly pulled from the php manual's static keyword comments:
Because php does not have a static constructor and you may want to initialize static class vars, there is one easy way, just call your own function directly after the class definition.
for example.
<?php
function Demonstration()
{
return 'This is the result of demonstration()';
}
class MyStaticClass
{
//public static $MyStaticVar = Demonstration(); //!!! FAILS: syntax error
public static $MyStaticVar = null;
public static function MyStaticInit()
{
//this is the static constructor
//because in a function, everything is allowed, including initializing using other functions
self::$MyStaticVar = Demonstration();
}
} MyStaticClass::MyStaticInit(); //Call the static constructor
echo MyStaticClass::$MyStaticVar;
//This is the result of demonstration()
?>
Simple and no magic needed, don't forget you can always define a variable as null and test that it is null (doing the db call only then). Then it's just a matter if you want that to happen when the class is constructed or included (include_once etc...)
MyClass extends BaseClass {
protected static $type = "communities";
protected static $typeID = null;
public function __construct(){
if(is_null(self::$typeID)){
self::lookupTypeID(self::$type);
}
}
public static lookupTypeID($type){
self::$typeID = //result of database query
}
}
or
MyClass::lookupTypeID(); //call static function when class file is included (global space)
MyClass extends BaseClass {
protected static $type = "communities";
protected static $typeID = null;
public function __construct(){
}
public static lookupTypeID($type=null){
if(is_null($type)){
$type = self::$type;
}
self::$typeID = //result of database query (SELECT somefield FROM sometable WHERE type=$type) etc..
}
}
a static constructor is more like a factory method
if(!function_exists(build_myclass)){
function build_myclass(){
return MyClass::build();
}
}
MyClass extends BaseClass {
protected static $type = "communities";
protected static $typeID = null;
public function __construct(){
}
public static function build(){
return new self(); //goes to __construct();
}
}
$class = new MyClass(); //or
$class = MyClass::build(); //or
$class = build_myclass();
Such a thing would normally be called a "static constructor", but PHP lacks such things. You might want to consider one of the workarounds suggested in the PHP manual comments, e.g. http://www.php.net/manual/en/language.oop5.static.php#95217
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!