Calling an Abstract method from parent abstract class - php

After looking at this question, I tried the chosen answer myself!
So basically what I wrote was `
abstract class person
{
function __construct()
{
// some code here
}
function myfunc()
{
$this->test();
}
abstract function test();
}
class employee extends person
{
function __construct()
{
parent::__construct();
}
function test()
{
echo "So you managed to call me !!";
}
}
$employee = new employee();
$employee->myfunc();`
When I run this script, I got an usual error
Fatal error: Using $this when not in object context on line 7.
So, how do I call an Abstract from the Parent Class?
EDIT
The real thing which I am trying to do is create a DatabaseObject class which holds all the common methods of different database objects and make classes extend it.
abstract class DatabaseObject {
abstract protected function getTableName();
public static function find_by_id($id = 0){
global $database;
$class = get_called_class();
$result_array = self::find_by_sql("SELECT * FROM ". $this->getTableName() ." WHERE _id = {$id} LIMIT 1");
echo $result_array . "<br />";
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql=""){
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)){
$object_array[] = self::instantiate($row);
}
return $object_array;
}
}
}
So this is some part of my DatabaseObject Class. My User class is as follows
class User extends DatabaseObject {
protected static $table_name = "users";
protected function getTableName(){
global $table_name;
return $table_name;
}
}
Now, whenever I do
$user = new User();
$user->findById(1);
I get the error Fatal error: Using $this when not in object context
on the line which points to
$this->getTableName();
I hope this might help in clearing up some stuff. Is there any way I can achieve this?
Thanks!

Your code example works just fine, I don't understand your issue Demo.
So the code you've shared is not the code you talk about with the error .

You can not call the variable as if it were a member of the class, since you declared it static. Calls to static variables looks the same as when you call static functions, use the :: operator.
class User extends DatabaseObject {
protected static $table_name = "users";
protected function getTableName(){
return self::$table_name;
}
}

The first thing is you can not call the abstract function within the same class. You are calling test(); in side myfunc() which is not allowed by oops.

You cant access the abstract function inside the same abstract class.
What ever your needs are, you have to call that method in sub class only, abstract super class will not call the sub class function.
EDIT:
Because the function dosent exists in that class.

Related

Pass arguments to parent class constructor in PHP?

I have 2 classes where parent is inherited by child.
class parentClass
{
private $table_name='';
public function __construct($argument)
{
$this->table_name=$argument;
echo $this->table_name;
}
}
class child extends parentClass
{
private $table="student";
public function __construct()
{
parent::__construct($this->table);
}
}
There is some thing like this below that has to be used but I am unable to understand how and why.
$args = func_get_args();
call_user_func_array(array($this, 'parent::__construct'), $args);
Help me as
What should be the correct code to achieve the correct logic
and please support it with a reference to gain a better understanding.
Not a direct answer, but if I read the code correctly, you don't really want to pass a variable / value to the constructor. Instead you want to pass a fixed class property like a table name.
In that case you could use a constant in the child class and set that in the parent's constructor. The child class would not need a separate constructor if that is all you want to do.
So something like:
class parentClass
{
private $table_name;
function __construct() {
$this->table_name = static::TABLE;
echo $this->table_name;
}
}
class childClass extends parentClass
{
const TABLE = "student";
}
$obj = new childClass();

PHP Object Oriented array not being printed

Alright so I got 2 problems on my hands at the moment and those are
I want to call the function from the parent object but I am getting a lot of errors saying "Fatal error: Cannot instantiate abstract class Person"
If I call the getUserItems directly it will not do anything. There wont be anything echoed or such.
<?php
abstract class Person {
abstract function getUserItems();
}
class inventory extends Person {
protected $storage = array();
protected $item_id;
public function itemAdd($itemname) {
$storage[$this->item_id+1] = $itemname;
}
public function getUserItems() {
foreach($this->storage as $itemName=>$item_id) {
echo $itemName." ".$item_id."<br/>";
}
}
}
$user = new Person();
$user->getUserItems();
/*$user = new inventory();
$user->itemAdd("Item 1");
$user->itemAdd("Item 2");
$user->getUserItems();*/
?>
In OOP - abstract class may not be instantiated.
An abstract class is a class with both implementation and interface (pure virtual methods) that will be inherited. Interfaces generally do not have any implementation but only pure virtual functions.
So you cannot instantiate (new Person()). You must extend this abstract class and implement it's abtract functions (same way you did in inventory).
Regarding the echoing problem - inside your itemAdd function you didn't use the object's $storage member (you just used a local $storage variable). You should use it as the object's memebr, using $this->storage:
public function itemAdd($itemname) {
$this->storage[$this->item_id+1] = $itemname;
}
Note that I'm not so sure how you managed the $this->item_id member because you didn't set/changed it in the code.
If you only want to add new items to the storage member you could use:
$this->storage[] = $itemname;
This will make sure every new item will be added to the $storage array.
ad1)
Person is abstract class so you can not create object of that class.
ad2)
You must use $this
so not:
$storage[$this->item_id+1]
but
$this->storage[++$this->item_id]
Here I fixed another bug which was $this->item_id+1
Abstract class can not access directly but access from other class.
abstract class Person {
abstract function getUserItems();
}
class inventory extends Person {
protected $storage = array();
protected $item_id=2;
public function itemAdd($itemname) {
$storage[$this->item_id+1] = $itemname;
}
public function getUserItems() {
foreach($this->storage as $itemName=>$item_id) {
echo $itemName." ".$item_id."<br/>";
}
}
}
$user = new inventory();
$user->getUserItems();
$user = new inventory();
$user->itemAdd("Item 1");
$user->itemAdd("Item 2");
$user->getUserItems();

Best OOP design pattern for static class DbTable

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']);

Assigning a class variable from subclass without constructor

lI am building a light-weight Model layer for my project's database access.
I would like it to be in the spirit of Ruby on Rails. Instead of instantiating a new Model
object, I want to use a singleton approach. Here is the current issue I am facing:
class BaseModel {
public static $name;
public static function get($id) {
echo "SELECT * FROM ". self::$name ."s WHERE ". self::$name .' = '.$id;
}
}
class Customer extends BaseModel {
//parent::$name = 'customer'; => ERROR
}
$c = Customer::get(4);
Is there some way to assign the parent's static members in the class body? I would like
to avoid creating an actual singleton class if possible. Thanks.
The feature you are looking for is called Late Static Binding (LSB) and thankfully has been introduced to PHP in 5.3. You may read about it here: http://php.net/manual/en/language.oop5.late-static-bindings.php
This is your code rewritten using LSB.
<?php
class BaseModel {
public static $name;
public static function get($id) {
echo "SELECT * FROM ". static::$name ."s WHERE ". static::$name .' = '.$id;
}
}
class Customer extends BaseModel {
public static $name = 'customer';
}
$c = Customer::get(4);
?>

PHP const/static variables not usable in static context by parent class

For some reason (which?), PHP const/static variables defined in a child class are not usable in a static context by the parent class.
Why?
Example 1:
class Model{
function getAll(){
$query = "SELECT * FROM " . self::DATABASE_TABLE_NAME;
// ...
}
}
class Post extends Model{
const DATABASE_TABLE_NAME = 'post';
}
$p = Post::getAll();
When I run that I get:
Fatal error: Undefined class constant 'DATABASE_TABLE_NAME' on line 3
(The row with $query = ...)
Example 2:
class Model{
function getAll(){
$query = "SELECT * FROM " . self::$DATABASE_TABLE_NAME;
// ...
}
}
class Post extends Model{
static $DATABASE_TABLE_NAME = 'post';
}
$p = Post::getAll();
Then I get:
Fatal error: Access to undeclared static property: Model::$DATABASE_TABLE_NAME on line 3
(Same row)
PHP5.3 introduced late static binding — that's what you're looking for.
class ParentClass {
public function getAll() {
var_dump('Get all from ' . static::TABLE_NAME);
}
}
class ChildClass extends ParentClass {
const TABLE_NAME = 'my_table_name';
}
$c = new ChildClass();
$c->getAll(); // Get all from my_table_name
EDIT:
However you should design your classes a little bit different. The above solution relies on language dynamics (you can refer to something (eg. a class constant) that doesn't even exists). In such a simple example everything is fine but in real word cases this leads to producing horrible and hard to maintain code.
It'd be better to force the delivered class (ChildClass) to implement some method that returns table name:
abstract class ParentClass {
// getAll function
abstract protected function getTableName();
}
class ChildClass extends ParentClass {
// You have to implement this method
protected function getTableName() {
return 'table name';
}
}
I found the answer here:
How can I get the classname from a static call in an extended PHP class?
Solution:
class Model{
function getAll(){
$class = get_called_class();
$query = "SELECT * FROM " . $class::$DATABASE_TABLE_NAME;
// ...
}
}
class Post extends Model{
static $DATABASE_TABLE_NAME = 'post';
}
$p = Post::getAll();
There all available.
Under the static context you should be using late static binding so that the code would become:
$query = "SELECT * FROM " . static::$DATABASE_TABLE_NAME;
i would also advise you to use constants for sanity reasons.

Categories