How to solve Creating default object from empty value? - php

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

Related

Can't access construct variable in method ( php laravel )

I have a base class which sets up's other extending controllers like this:
class BaseController extends Controller
{
public $globalCurrencies;
public $globalLanguages;
public function __construct()
{
$this->globalCurrencies = $this->getCurrencies(); // this works
$this->globalLanguages = $this->getLanguages(); // this works
}
}
And I use one of helpers to extend this class like this:
class SessionHelper extends BaseController
{
public $test;
public function __construct()
{
parent::__construct(); // fire parent aka basecontroller construct
$this->test = $this->globalCurrencies; // this works (variables are set)
echo '__construct: '.$this->test; // this even displays it
}
public function getCurrencies()
{
dd('method'.$this->test); // NOT WORKING
}
public function getCurrentCurrency()
{
return $this->getCurrencies()->where('id', Session::get('currencyId'))->first() ?? null;
}
}
Later on code is used in model:
class Product extends Model
{
protected $table = "products";
public $timestamps = true;
public $sessionHelper;
public function __construct()
{
$this->sessionHelper = new SessionHelper;
}
public function getPrice($conversion_rate = null)
{
return number_format($this->price_retail / $this->sessionHelper->getCurrentCurrency()->conversion_rate, 2);
}
}
Have any body idea why I can access in construct variable but not in method? If i remember correctly construct is fired first so everything after should have access to it.
Declare $test variable as private out side the constructor. Inside the constructor keep it the way you are doing it right now and then make a setter and getter for the test variable.
class testObject
{
private $test;
function __construct($test)
{
$this->test= $this->globalCurrencies;
}
// test getter
function getTest()
{
return $this->test;
}
}
Change your method to be;
public function getCurrencies()
{
dd('method', $this->test);
}
You can not concatenate strings and objects/arrays.
If that doesn't resolve the issue - check the laravel.log

PHP How to make 2 classes access methods from each one

I have a simple php code and I want to split it into model,view,helper. Model should access some methods from helper class and helper class should access some methods from model class.
I am not sure if the below pattern is correct. I guess it is not because in this example model,view,helper will be initialized multiple times. Which is the most simple way to accomplish something like I am trying to do with the below code?
lib/main.php
require_once('lib/model.php');
require_once('lib/helper.php');
require_once('lib/view.php');
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'show';
switch($action){
case "show":
$class->showAction();
break;
case "another":
$class->anotherAction();
break;
}
class main extends abstract{
public function showAction(){
if($this->helper->getParam('browse')){
//something
}else{
$profiles= $this->model->getProfiles();
}
echo $this->view->toHtml($profiles);
}
}
lib/abstract.php
class abstract{
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper();
}
}
lib/model.php
class model extends abstract{
public function getProfiles(){
if($this->helper->someMethod(){
//some code
}
//some code
return $profiles;
}
}
lib/helper.php
class helper extends abstract{
public function someHelperMethod(){
if($this->model->someAnotherMethod(){
//some code
}
//some code
return $profiles;
}
}
First problem is that you are nesting your classes like russian dolls. You shouldn't have your Abstract class both contain model/view/helper, and be the parent of model/view/helper.
I'd caution against using extension just to ensure a class is in-scope.
Generally you can think of it this way: use extension when your class has shared behaviors or properties as it's parent, but it either needs additional functionality, or modifications to existing functionality.
The "abstract" class you defined shares no attributes or methods between Model/View/Helper, so Model/View/Helper should not probably extend from it.
If however you want a "container" class that contains instances of each of these class types, just make it a standalone class, don't extend it, for example:
class Container{
public $model;
public $view;
public $helper;
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper();
}
public function showAction(){
if($this->helper->getParam('browse')){
//something
}else{
$profiles= $this->model->getProfiles();
}
echo $this->view->toHtml($profiles);
}
Then instantiate it only once at the start someplace:
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'show';
$class = new Container();
Then, if you want to call something from Model inside Helper, this can be done a number of ways.
One option, pass a reference to this class and keep it inside Helper:
// Inside Container
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper($model);
}
The Helper class would look like:
class Helper{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function someHelperMethod(){
if($this->model->someAnotherMethod()){
//some code
}
//some code
return $profiles;
}
}

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

PHP declare class variable from another instance

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

Testing a private method in an abstract class extends the other one

I'm trying to test a private method in an abstract class.
I've got three abstract classes:
abstract class AbstractClass1 extends AbstractClass2
{
private function _privateFunction()
{
//method's body
}
}
abstract class AbstractClass2 extends AbstractClass3
{
public function __construct($param)
{
parent::__construct($param)
}
}
abstract class AbstractClass3
{
public function __construct($param = array())
{
//something
}
}
The test class:
class AbstractClass1Test extends PHPUnit_Framework_TestCase
{
public function test_privateFunction()
{
$stub = $this->getMockForAbstractClass("AbstractClass1");
$class = new ReflectionClass($stub);
$method = $class->getMethod("_privateFunction");
$method->setAccessible(true);
//some assertings with $method->invoke($stub)
}
}
The test failed, because of the error:
Missing argument 1 for AbstractClass2::__construct(), called in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php on line 190 and defined
AbstractClass2.php
public function __construct($param)
AbstractClass1.php
$classMock = $this->getMockForAbstractClass("AbstractClass1");
Generator.php:190
if ($callOriginalConstructor &&
!interface_exists($originalClassName, $callAutoload)) {
if (count($arguments) == 0) {
<strong>$mockObject = new $mock['mockClassName'];</strong>
} else {
$mockClass = new ReflectionClass($mock['mockClassName']);
$mockObject = $mockClass->newInstanceArgs($arguments);
}
} else ...
What do I wrong? Or how can I test my private function in this situation?
You need to pass an argument to AbstractClass1's constructor. Pass constructor arguments in an array as the second argument to getMockForAbstractClass().
$stub = $this->getMockForAbstractClass("AbstractClass1", array('param'));
Seeing as you overrode the original constructor,
public function __construct($param = array()) //Allow null $param as it would default to array();
With a new one:
public function __construct($param) //Does not allow null $param.
You will require to define the $param when you initialize the object. That's probably your problem.
Objects in PHP are not like JavaScript, they cannot be called like associative arrays. Your object initialization should look like:
$mockObject = new ClassExtendingAbstractClass1Or2('parameter');
The new keyword cannot be used in front of a variable.

Categories