PHP- share class variable with a child class - php

This is a follow up from yesterday's scope question.
stackoverflow.com/questions/3301377/class-scope-question-in-php
Today I want to share the "$template_instance" variable with a child class.
How is this accomplished?
require_once("/classes/Conf.php");
require_once("/classes/Application.php");
class index extends Application
{
private $template_instance;
// Dependency injection
public function __construct(Smarty $template_instance)
{
$this->template_instance = $template_instance;
}
function ShowPage()
{
// now let us try to move this to another class
// $this->template_instance->assign('name', 'Ned');
// $this->template_instance->display('index.tpl');
}
}
$template_instance = new Smarty();
$index_instance = new Index($template_instance);
//$index_instance->showPage();
$printpage_instance = new printpage();
$printpage_instance->printSomething();
------------------------------------------------------------------
class printpage
{
public function __construct()
{
}
public function printSomething()
{
// now let us try to move this to another class
$this->template_instance->assign('name', 'Ned');
$this->template_instance->display('index.tpl');
}
}

Make it protected. Protected members will be accessible to the class and its children only.
Visibility Overview
Public members: members that
are visible to all classes.
Private variables: members that
are only visible to the class
they belong to.
Protected variables: members
that are only visible to the class
in which they belong as well as any of its children (subclasses)

In exactly the same way you were told before
$printpage_instance = new printpage($template_instance);
$printpage_instance->printSomething();
------------------------------------------------------------------
class printpage
{
private $template_instance;
public function __construct(Smarty $template_instance)
{
$this->template_instance = $template_instance;
}
public function printSomething()
{
// now let us try to move this to another class
$this->template_instance->assign('name', 'Ned');
$this->template_instance->display('index.tpl');
}
}
or pass your index to the printpage constructor
$printpage_instance = new printpage($template_instance);
$printpage_instance->printSomething();
------------------------------------------------------------------
class printpage
{
private $index;
public function __construct(index $index)
{
$this->index = $index;
}
public function printSomething()
{
$this->index->ShowPage();
}
}

Related

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 Change parent class at runtime?

I have a parent class that depends on whether child class are instantiated.
class GoogleApp {
protected $auth_token;
public function __construct($scopes) {
$this->auth_token = $scopes;
}
}
class Gmail extends GoogleApp {
public function __construct() {
print_r($this->auth_token);
}
}
$googleApp = new GoogleApp('gmail'); // Change the actual class for all child instances
$gmail = new Gmail();
The idea is that all the children use the same auth_token (which is generated on whether the child classes are used - as of now, I'm just manually adding them to whether I included them in my code). Since I have quite a few child classes (like Calendar or Drive), do I have to inject the parent into each child instance or is there an easier way?
If I understand your request correctly, you're pretty close, you just need to declare your property as static.
class FooParent
{
protected static $scope = null;
public function __construct($scope)
{
self::$scope = $scope;
}
public function getScope()
{
return self::$scope;
}
}
class FooChild extends FooParent
{
public function __construct()
{
if (self::$scope === null) {
throw new Exception('Must set scope first.');
}
}
}
$parent = new FooParent('foo');
$child = new FooChild();
echo $child->getScope(), "\n"; // prints "foo"

How do I access parent property from subclass? PHP

I have an issue accessing top level variables from sub-level class.
Here's an example...
Application.php:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database;
}
}
Configuration.php:
class Configuration {
var $dbhost = 'localhost';
}
Database.php:
class Database {
function __construct() {
echo parent::config->dbhost;
}
}
It is clear to me that usage of parent is wrong here as the subclass does not extend the parent class, but how do I access it?
Thank you.
You should create a Base class that in its construct creates a $db link. Then let all classes that require database access extend that class. Your nomenclature here with "parent class" is incorrect.
class Base {
private $db; // Make it read-only
function __construct() {
$this->db = DB::connect(); // It's a good practice making this method static
}
function __get($property) {
return $this->$property;
}
}
class Application {
public $config;
function __construct() {
parent::__construct();
require_once 'Configuration.php';
require_once 'Database.php';
$this->config = new Configuration();
}
function random_function() {
$this->db(....) // Has full access to the $db link
}
}
The parent notation is used to access the parent of the object in the object hierarchy. What you are doing here is trying to get at the caller, not the parent
The way that you would do this is to pass in an instance of your configuration to the database object.
class Database {
protected $config;
public function __construct(Configuration $config){
$this->config = $config;
}
public function connect(){
//use properties like $this->config->username to establish your connection.
}
}
The parent notation is used when you extend a class and make a child class to call methods on the parent .
class MySuperCoolDatabase extends Database {
protected $is_awesome;
public function __construct(Configuration $config){
// do all the normal database config stuff
parent::__construct($config);
// make it awesome
$this->is_awesome = true;
}
}
This defines a child class, which is a type definition that serves the same role as the base class with a slightly different implementation. Instances of this can still be said to be a Database.... just a different kinds of database.
Well, although I think that Orangepills answer is better. If you dont want to use it and since all variables are public, you could simply pass the variable like this:
class Application {
var $config;
var $db;
function __construct() {
include_once('Configuration.php');
include_once('Database.php');
$this->config = new Configuration;
$this->db = new Database($this->config->dbhost);
}
}
class Configuration {
var $dbhost = 'localhost';
}
class Database {
function __construct($dbhost) {
echo $dbhost;
}
}

Wrap/Reuse/Clone a PHP object (code optimization)

Imagine two classes which share almost the same exact methods and properties, both extending a parent class, but the differences are minimal.
class fields {
public function __construct() {
global $id;
$this->id = $id++;
}
}
class input extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<textarea>';
}
}
I'm thinking it would be more efficient to rewrite the textarea class in this psuedo-code fashion:
class textarea extends fields {
public function __construct() {
$this = new input(); // <<------
}
public function draw() {
echo '<textarea>';
}
}
Basically, I'm unsure how this would best be done so that the class acts like the class from the first example.
In essence, I would like to do the following using OOP, but be able to use the object as it can be in the first example above (be able to call the possibly overloaded methods, have different properties, etc.):
function a() {echo '123';}
function b() {a();}
I have just copied the entire class and modify a few lines, but I feel it is wasteful.
Final Answer
Thanks to those people, here is the combined answer with example calls:
abstract class fields {
private static $masterid = 0;
public function __construct() {
$this->id = self::$masterid++;
}
}
class input extends fields {
public $data;
public function __construct($new = '') {
parent::__construct();
if ($new) $this->data = $new;
else $this->data = 'Hello';
}
public function draw() {
echo '<input>'.$this->export().'</input>';
}
public function export() {
return 'ID '.$this->id.' = '.$this->data;
}
}
class textarea extends input {
public function __construct($new = '') {
parent::__construct($new);
}
public function draw() {
echo '<textarea>'.$this->export().'</textarea>';
}
}
$a = new textarea();
$a->draw();
$a = new textarea('World');
$a->draw();
$a = new input('!');
$a->draw();
//Outputs:
// <textarea>ID 0 = Hello</textarea>
// <textarea>ID 1 = World</textarea>
// <input>ID 2 = !</input>
Make the fields class an abstract class, and like Darren suggested, make the 'draw' method a function of the fields class.
Now heres the trick, you want the input class to extend fields, but override the draw method. This will allow you to customize the functionality of that method, and you can still call the parent variation from within it.
Finally, since the textarea class is going to have many similarities to the input class, make textarea extend input. Thereby inheriting the properties and methods of both fields and input.
Make the "fields" class have a draw method:
public function draw($msg) {
echo $msg;
}
Then in the textarea or input class put:
parent::draw("<input>");
This cuts down on the number of methods you have, and can call one method for both types of field.
Also in your "fields" class, change the id code to be like this:
public $id
public function __construct($id) {
$this->id = $id;
}
Then in the subclass:
parent::__construct(1); //Or whatever ID you want
The way you have it, ID is the same value every time you set it, which will result in every subclass of fields having the same id. This way each subclass will have a seperate ID.
Also because I'm nice, here's it all put together:
public class field {
$id;
public __construct($id) {
$this->id = $id;
}
public function draw($msg) {
echo $msg;
}
}
public class input extends field {
public __construct() {
parent::__construct(1);
parent::draw("<input>");
}
}
public class textarea extends field {
public __construct() {
parent::__construct(2);
parent::draw("<textarea>");
}
}
That's how I'd put it together from what you've said. I may have mistaken what you were asking for though. Can you tell I'm primarily a Java programmer from that?
It's not exactly clear what you want to do. For the example you've given, I think the structure is OK, but you should make a few changes, particularly with the constructor. I think the constructor should be abstract, with an abstract method draw().
abstract class fields {
// Use a static member to keep track of id's instead of making it global
private static $id = 0;
// Use an instance variable to keep track of a particular instance's id
private $myId;
public function __construct() {
// Increment the static ID & assign it to the instance id.
$this->myId = self::$id++;
}
// Provide a public getter, so that the ID can't be changed
// externally to this class
public function getId() {
return $this->myId;
}
public abstract draw(); // Make sure all sub classes implement a draw() method.
}
class input extends fields {
// Don't need to call the parent constructor if you're not adding anything
// else. It will be called automatically.
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function draw() {
echo '<textarea>';
}
}

2 New Instances of a Parent and Child class, need to change Parent variable directly in parent and view in child

PHP
If I create a new instance of a parent class and a new instance of a child class, how can I change the variable in the parent class directly and view the change in the child class?
Take the following code:
class parentClass {
public $varA = 'dojo';
public function setVarA() {
$this->varA = 'something grand';
}
public function getVarA() {
return $this->varA;
}
}
class childClass extends parentClass {
public function useVarA() {
echo parent::getVarA();
}
}
$parentInstance = new parentClass();
$childInstance = new childClass();
$initialVarA = $parentInstance->getVarA(); // should set $initialVarA variable to 'dojo'
$childInstance->useVarA(); // should echo 'dojo'
$parentInstance->setVarA(); // should set $varA to 'something grand'
$changedVarA = $parentInstance->getVarA(); // should set $changedVarA variable to 'something grand'
$childInstance->useVarA(); // should echo 'something grand' but fails to do so...how can I do this?
If you have either a private or a protected variable (member) in the parent then you can access it simply like this from you child class:
$this->varA = ‘something’;
There reason why your child method does not reflect the change, is that child and parent are two different objects in separate memory space. If you want them to share a value you could make it static.
You don’t need to declare it public.
class Parent {
private $varA;
protected $varB;
public $varC;
protected static $varD;
public function getD() {
return self::$varD;
}
public function setD($value) {
self::$varD = $value;
}
}
class Child extends Parent {
public function getA() {
return $this->varA;
}
public function getB() {
return $this->varB;
}
public function getC() {
return $this->varC;
}
}
$child = new Child();
$child->getA(); // Will not work since $varA is private to Parent
$child->getB(); // Works fine because $varB is accessible by Parent and subclasses
$child->getC(); // Works fine but ...
$child->varC; // .. will also work.
$child->getD(); // Will work and reflect any changes to the parent or child.
If you don’t want all instance of the parent class to share values. You could pass on the parent or child to either new instance and through and update the values of all the related objects accordingly.
$parent->addChild(new Child());
And in the set method:
$this->varA = $value;
foreach ($this->children as $child) {
$child->setVarA($value);
}
Hopes this helps.

Categories