Return instance of class from base class - php

I'd like to create an object like so:
class Obj extends BaseModel {
public function doSomething() {
// do some stuff with the instance
}
}
class BaseModel {
public static function find($id){
// retrieve object from database and return instance of Obj class
}
}
So i can achieve the following:
$obj1 = Obj::find(1);
$obj1->doSomething();
How can I create this so that the static method from the base class returns an instance of the Obj class?
(similar to how Laravel handles objects)

In your base model, you can get the class of the children that's been called with get_called_class.
class Obj extends Base{
private $id;
public function __construct($id){
$this->id = $id;
}
public function getId(){
return $id;
}
}
class Base{
public static function find($id){
$class = get_called_class();
return new $class($id);
}
}
Example
$obj = Obj::find(1);
var_dump of $obj
object(Obj)#1 (1) {
["id":"Obj":private]=>
int(1)
}

Related

PHP7.3: How can I inherit a protected static property with the thightest possible scope without redeclaring it in the child class?

In the application I'm working on, the Model part of the MVC stack is designed to work trough singletons; each Model has a __getInstanceMethod which is
protected static $singleton;
public static function __getInstance(): self {
if(self::$singleton === null) {
self::$singleton = __CLASS__;
self::$singleton = new self::$singleton;
}
return self::$singleton;
}
End result is, if __getInstance() is called twice on the same Model class, it returns the same exact object both times.
I tried to reduce code duplication by moving the __getInstance() method to the Model's parent class, BaseModel, by editing it like so.
class BaseModel {
protected static $singleton;
public static function __getInstance(): self {
if (static::$singleton === null) {
static::$singleton = static::class;
static::$singleton = new static::$singleton();
}
return static::$singleton;
}
}
class AModel extends BaseModel {
protected static $singleton;
/** ... */
}
class BModel extends BaseModel {
protected static $singleton;
/** ... */
}
AModel::__getInstance(); // AModel
BModel::__getInstance(); // BModel
Problem is, I need to manually add a $singleton property to each and every Model class, otherwise I'll always get returned the instance of the first Model class I called the method on.
class BaseModel {
protected static $singleton;
public static function __getInstance(): self {
if (static::$singleton === null) {
static::$singleton = static::$class;
static::$singleton = new static::$singleton();
}
return static::$singleton;
}
}
class AModel extends BaseModel {}
class BModel extends BaseModel {}
AModel::__getInstance(); // AModel
BModel::__getInstance(); // Still AModel
Is there a way I can avoid doing that?
You could switch to an "instance map", e.g.:
<?php
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'On');
class BaseModel
{
protected static $instances = [];
public static function __getInstance(): self
{
if (!isset(static::$instances[static::class])) {
static::$instances[static::class] = new static();
}
return static::$instances[static::class];
}
}
class AModel extends BaseModel
{
}
class BModel extends BaseModel
{
}
echo get_class(AModel::__getInstance()), "\n";
echo get_class(BModel::__getInstance());
https://3v4l.org/qG0qJ
and with 7.4+ it could be simplified to:
<?php
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'On');
class BaseModel
{
private static array $instances = [];
public static function __getInstance(): self
{
return static::$instances[static::class] ??= new static();
}
}

Calll a function from child class

Given I have an abstract class:
abstract class User{
private function getNumber(){
return 'Get number';
}
}
With the child class
class UserComments extends User{
public function rows(){
return $this->getNumberOfRows();
}
}
Question:
Is there any way to call the getNumber function when I try to call getNumberOfRows method in child class, or when I call getNumberOfRows() in child class I want getNumber to be called instead
?
Due to PHP's Object inheritance you can directly call the specific method. However, in your example the getNumberOfRows() function is missing.
class UserComments extends User {
public function rows() {
return $this->getNumber();
}
}
You can do something like this
abstract class User{
private function getNumber(){
return 'Get number';
}
public function getNumberOfRows(){
return $this->getNumber();
}
}
With the child class
class UserComments extends User{
public function rows(){
return $this->getNumberOfRows(); //Defined in the parent class
}
}
Abstract methods cannot be private, abstract must be implemented by the class that derived it.
You can either use public, or if you do not want it to be visible outside, make it protected, as following:
abstract class User{
abstract protected function getNumber();
}
Once you do this, you can implement the getNumber method in User class:
class User {
protected function getNumber() {
// Do something
}
}
Update: Please note that protected methods are accessible by child classes, you can use "hierarchy":
abstract class User{
abstract protected function getNumber();
}
class UserComment extends User {
protected function comment() {
// Do something
}
protected function getNumber() {
return 3;
}
}
class Post extends UserComment {
public function myMethod() {
echo $this->getNumber();
}
}
Also you can use interfaces, just an example:
interface User {
public function getNumber();
}
class UserComment {
protected function myMethod() {
// Do something
}
}
class Post extends UserComment implements User {
final public function getNumber() {
return 3;
}
public function myMethod() {
echo $this->getNumber();
}
}
$post = new Post();
$post->myMethod();

May I use properties from a parent class in a trait?

Is it OK to use properties/methods from parent classes in trait methods?
This code works, but is it good practice?
class Child extends Base{
use ExampleTrait;
public function __construct(){
parent::__construct();
}
public function someMethod(){
traitMethod();
}
}
trait ExampleTrait{
protected function traitMethod(){
// Uses $this->model from Base class
$this->model->doSomething();
}
}
I don't think it's good practice.
Instead you could have a method to fetch your model object, and have that method as an abstract signature in you trait:
trait ExampleTrait {
abstract protected function _getModel();
protected function traitMethod() {
$this->_getModel()->doSomething();
}
}
class Base {
protected $_model;
protected function _getModel() {
return $this->_model;
}
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod();
}
}
Or pass your model as a parameter to your trait method:
trait ExampleTrait {
protected function traitMethod($model) {
$model->doSomething();
}
}
class Base {
protected $_model;
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod($this->_model);
}
}
Both of these approaches let you utilize your IDE's type hinting.

abstract member functions fail to access atributes of inheriting class

in php I have this code. I'm trying to get an inherited method to utilize a member variable of its child class.
abstract class HtmlObj{
//abstract protected function jQuery_Activity();
public $hyperlink;
abstract protected function php_Activity();
abstract protected function print_Widget();
function __construct($hyperlink=""){
if(isset($hyperlink)){
$this->hyperlink = $hyperlink;
}
$this->php_Activity();
$this->Print_Widget();
}
}
class child extends HtmlObj{
public $id;
protected function php_Activity(){return;}
protected function print_Widget(){
print $this->id;
}
function __construct($id){
this->id = $id;
}
}
unfortunately this prints nothing. any insights as to why?
in child class You need to reffer to parent::__construct() by doing something like
abstract class HtmlObj
{
//abstract protected function jQuery_Activity();
public $hyperlink;
abstract protected function php_Activity();
abstract protected function print_Widget();
function __construct($hyperlink = "")
{
if (isset($hyperlink)) {
$this->hyperlink = $hyperlink;
}
$this->php_Activity();
$this->Print_Widget();
}
}
class child extends HtmlObj
{
public $id;
protected function php_Activity()
{
return;
}
protected function print_Widget()
{
print $this->id;
}
function __construct($id)
{
$this->id = $id;
parent::__construct();
}
}
new child(10);

Create this instance

i have hundred of class model (Model of MVC system).
How i can create instance with relational class?
example in class there is method like this:
class object {
/**
* Simply create new instance of this object
* #return object
*/
function createNewInstance() {
$class_name = __CLASS__;
$return = new $class_name;
return $return;
}
}
As we can see, i use __CLASS__ to get relational name if this class.
Is there any better way to create instance?
i heard there is reflection method to do it?
seems you need get_class()
http://codepad.org/yu6R1PDA
<?php
class MyParent {
/**
* Simply create new instance of this object
* #return object
*/
function createNewInstance() {
//__CLASS__ here is MyParent!
$class_name = get_class($this);
return new $class_name();
}
}
class MyChild extends MyParent {
function Hello() {
return "Hello";
}
}
$c=new MyChild();
$d=$c->createNewInstance();
echo $d->Hello();
this also works:
class MyParent {
/**
* Initialise object, set random number to be sure that new object is new
*/
function __construct() {
$this->rand=rand();
}
}
class MyChild extends MyParent {
function Hello() {
return "Hello ".$this->rand;
}
}
$c=new MyChild();
$d=new $c;
echo $c->Hello()."\n";
echo $d->Hello()."\n";

Categories