PHP declare class variable from another instance - php

I have a hard time figuring out how to add a variable value to an instantiated class in php,
I've been looking at the reflectionClass and tried to return an assigned variable, and now I'm ended up with a getter setter.
I would really appreciate some help, here's an example of my code:
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name');
}
}
class loader
{
public function set_model($name)
{
{controller_class}->models[$name] = new model();
}
}
The controller class is instantiated without assigning it to a variable, but just:
new controller();
And then the action is executed from within the controller class.

You could pass a reference to $this into set_model()
class controller
{
public $models;
private $load;
public function __construct()
{
$this->load = new loader();
}
public function action_being_run()
{
$this->load->set_model('model_name', $this);
}
}
class loader
{
public function set_model($name, &$this)
{
{controller_class}->models[$name] = new model();
}
}
You also need to change public $model to public $models. There are probably other ways to achieve what you want, by either extending a class or just using magic methods to access the model.

Like this:
class tester{
public function lame(){
return 'super lame';
}
}
function after(){
return 'after function';
}
$tst = new tester; $tst->afterVar = 'anything'; $tst->afterFun = 'after';
echo $wh->afterVar;
echo $wh->afterFun();

Related

How can I injected a function before call a function?

I have a problem, I cannot call a function before all functions.
I have a parent class - that is a repository.
class Repository {
public function find(/*..*/){/*..*/}
public function findAll(/*..*/){/*..*/}
public function findBy(/*..*/){/*..*/}
public function findA(/*..*/){/*..*/}
public function findB(/*..*/){/*..*/}
/* then 100+ more public function */
}
And I want to create an "Adapter class" that will be calling a function that run before all only public functions BUT I don't want "overwriting" all functions of the parent.
I tried this solution:
class OwnRepo extends Repository{
public __call($methods, $args){/**/}
}
BUT the __call method not working with public methods
How can I solve this problem?
Thank you!
** UPDATE **
Sorry I was not clear!
My controller implements a model, I don't want to change/rewrite the functions of the controllers.
class IndexController {
public function index(){
$model = new Model(); // will return a OwnRepo object
$a = model->findAll();
}
}
In my opinion you can't do this with inheritance. You have to check if the desired method exists in the Repository class and then call it.
Try this one:
class Repository
{
public function find($a,$b,$c)
{
return "find $a $b $c";
}
}
class OwnRepo
{
function __call($name, $arguments)
{
if (method_exists('Repository', $name)) {
//some action before
$repo = new Repository();
$result = call_user_func_array(array($repo, $name), $arguments);
//some action afterwards
return $result;
} else {
die("Method " . $name . " does not exist");
}
}
}
$o = new OwnRepo();
echo $o->find(1,2,3);

php access parent object of a subclass (no inheritance)

I have a core class as a collector and two subclasses stored in public variables in this core class:
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html();
}
}
class Cache
{
public function __construct()
{
}
public function store($value)
{
// do something
}
}
class Html
{
public $foo;
public function __construct()
{
$foo = "bar";
global $core;
$core->cache->store($foo);
}
}
QUESTION:
I would like to get rid of the line "global $core" and do something like:
$this->parent->cache->store($foo)
$cache should be connected to $core in some way because it is a public member of $core
I know that $html is a subclass stored as a variable and not an inheritance.
Any ideas?
Second question: Can I leave out the empty constructor in the Cache-Class?
What you can do is to use the concept of dependency injection to inject in your HTML class an object of the class Cache, and then, use it to call method store. I believe that this is a very good approach. So you can do something like this.
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html($cache);
}
}
In your class HTML:
class Html
{
public $foo;
public function __construct(Cache $cache)
{
$foo = "bar";
$cache->store($foo);
}
}
About your second question, if there is no necessity of do something in the constructor, you could just ommit it. But there is no problem to let it empty as well. So I think that it up to you.
Your object can't access caller class methods, because he do not know anything about it's caller.
You can try to pass parent when creating new object
class Core {
public $cache;
public $html;
public function __construct() {
$this->cache = new Cache($this);
$this->html = new Html($this);
}
}
class Html {
public $parent;
public function __construct($parent) {
$this->parent = $parent;
if (!empty($this->parent->cache)) {
$this->parent->cache->store();
}
}
}
Can I leave out the empty constructor - yes, you even do not have to declare __construct method at all, as all classes has it's default constructor/destructor.

return type of container from subclass

I have a PHP library which I don't want to edit, and implement to my code by extending/overriding some methods. But I'm stuck with chainability. For example:
class MomentPHP extends Moment {
public $uniqueSettings;
public function formatJS(){
return parent::format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
I want to do this:
$momentphp = new MomentPHP();
$dateStart = $momentphp->startof('month')->formatJs();
And the way to do this is overriding all the methods in the child class inside MomentPHP to return itself.
Is there any other simple way to do this? like using _call or something?
Edit: Found one way to do this:
Remove the inheritance,
Create a instance variable of parent class,
use __call method to switch between classes.
Like this:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
}
public function __call($method,$args){
if(in_array($method, get_class_methods($this))){
call_user_func(array($this,$method),$args);
else
call_user_func(array($this->instance,$method),$args);
return $this;
}
public function formatJS(){
return $this->instance->format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
Is there any better way?
One proper way to do this is:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
// settings etc.
}
public function __call($method,$args){
$result = NULL;
if(in_array($method, get_class_methods($this))){
$result = call_user_func(array($this,$method),$args);
else
$result = call_user_func(array($this->instance,$method),$args);
if($result instanceof Moment)
$this->instance = $result;
return $this;
}
public function format(){
return $this->instance->format($this->uniqueSettings);
}
}
Updating the instance from the method result is the key operation, and using $this instead of $this->instance allows you to use the extender class in every call. So you can override the function while using other methods in the parent class with chaining ability.

How to solve Creating default object from empty value?

I found something about this error but I think this is little bit different. I defined a public variable.
Class Controller{
public $model;
And I'm trying add extra word(model) between $model_name and $this.
public function call_model($model_name){
$this->model->$model_name = new $model_class;
What is the solution?
EDIT:
Warning: Creating default object from empty value in C:\xampp\htdocs\alisveris\project_library\Controller.php on line 16
You can create static factory method to create different models like this:
abstract class Model {
static function CallModel($name) {
switch ( $name ) {
case 'Naomi': return new NaomiCampbell();
case 'Anja': return new AnjaRubik();
default: return new $name;
}
}
}
class NaomiCampell extends Model {}
class AnjaRubik extends Model {}
Then use:
$MyModel = Model::CallModel($name);
You can do it by assigning $model variable to $this
class Db
{
public function great()
{
echo 'great';
}
}
class Controller{
public $model;
public function __construct()
{
$this->model = $this;
$model_name = 'Db';
$this->model->$model_name = new $model_name;
}
}
$cc = new Controller();
echo $cc->model->Db->great();
Output
great

Instance as a static class property

Is it possible to declare an instance of a class as a property in PHP?
Basically what I want to achieve is:
abstract class ClassA()
{
static $property = new ClassB();
}
Well, I know I can't do that, but is there any workaround beside always doing something like this:
if (!isset(ClassA::$property)) ClassA::$property = new ClassB();
you can use a singleton like implementation:
<?php
class ClassA {
private static $instance;
public static function getInstance() {
if (!isset(self::$instance)) {
self::$instance = new ClassB();
}
return self::$instance;
}
}
?>
then you can reference the instance with:
ClassA::getInstance()->someClassBMethod();
An alternative solution, a static constructor, is something along the lines of
<?php
abstract class ClassA {
static $property;
public static function init() {
self::$property = new ClassB();
}
} ClassA::init();
?>
Please note that the class doesn't have to be abstract for this to work.
See also How to initialize static variables and https://stackoverflow.com/a/3313137/118153.
This is a few years old, but I just ran into a issue where I have a base class
class GeneralObject
{
protected static $_instance;
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance))
{
self::$_instance = new $class;
}
return self::$_instance;
}
}
That has a Child Class
class Master extends GeneralObject
{
}
And another Child class
class Customer extends Master
{
}
But when I try to call
$master = Master::getInstance();
$customer = Customer::getInstance();
then $master will be Master as expected, but $customer will be Master because php uses the GeneralObject::$_instance for both Master and Customer
The only way I could achieve what I want was to change the GeneralObject::$_instance to be an array and adjust the getInstance() method.
class GeneralObject
{
protected static $_instance = array();
public static function getInstance()
{
$class = get_called_class();
if(!isset(self::$_instance[$class]))
{
self::$_instance[$class] = new $class;
}
return self::$_instance[$class];
}
}
I hope this helps someone else out there. Took me a few hours to debug what was going on.

Categories