I have a class base which has a property called load which is a object of the class load. The load class has a function called view that includes pages. Now I need to call,
This is similar to CodeIgniter's $this->load->view("test.php");
Load Class
class Load {
public function view($page){
//this function loads views to display
include($page);
}
public function model($class){
//loads model classes
}
public function library($class){
//loads libraries
}
}
Base Class
class Base {
function __construct(){
$this->load = new Load();
}
}
Index page
$base = new Base();
$base->load->view("test1.php");
this1.php
echo "testing1\n";
$this->load->view("test2.php");
test2.php
echo "testing2";
The output should be
testing1
testing2
What you really want I think is to follow a factory pattern. (At least, that's what you mean if you want the $view variable to actually contain an instance of the Load class)
Make the constructor protected, so that the only the class can create new instances, then in the base class add a static method, e.g. 'factory' which returns an instance of the desired class.
Then your code would look like
$view=Base::factory();
$view->view("test1.php");
NOTE: this answer was made before any edit made to the question. Please evaluate accordingly
You need to have the functions marked as public to allow them to be called from outside of the defining class (this is simplified of course)
Try the following:
class Load{
public function view($page){
include($page);
}
}
class Base{
public $load;
function __construct(){
$this->load = new Load();
}
}
(The uppercase class names are my own preference)
This should work, but it's not a good design from a clean OOP perspective, because the users of the Base class need to know how the Load class works. This is called "tight coupling" and should be avoided as much as possible.
I suggest to consider the following alternative:
class Load{
public function view($page){
include($page);
}
}
class Base{
private $load; //note the private modifier
function __construct(){
$this->load = new Load();
}
public function view($page){
$this->load->view($page);
}
}
This way I just need to know that Base has a method view($page) and i don't have to know anymore what Load does at all.
If in the future you want to change the Load class you can do it under the hood without the Base users ever noticing it, if you do it right:
Suppose you define a class:
class BetterLoad {
private function foo(){
//do something awesome
}
private function advancedView($page){
include($page);
$this->foo();
}
}
and you want to incorporate this inside Base instead of the old Load.
class Base{
private $adv_load; //note the private modifier
function __construct(){
$this->adv_load = new BetterLoad();
}
public function view($page){
$this->adv_load->advancedView($page);
}
}
That's it. You won't need to change anything else in your code. Just go on using the old $base_obj->view($page) and you're good to go, without even noticing the change.
Related
I have to different classes in my Slim PHP framework, named OrderController & AddressController. I want to access some function of AddressController inside OrderController to reduce code redundancy.
But can't get a way to do it, I got how to do it in pure PHP setup, but how to do it in Slim PHP framework?
The PHP way to do this is as follows:
class A {
private $xxx;
public function __construct() {
$this->xxx = 'Hello';
}
public function getXXX() {
return $this->xxx;
}
}
class B {
private $a;
public function __construct(A $a) {
$this->a = $a;
}
function getXXXOfA() {
return $this->a->getXXX();
}
}
$a = new A();
$b = new B($a);
$b->getXXXOfA();
How to achieve this dependancy injection in Slim?
Slim PHP Framework
Note: I am using Slim PHP v3
2 solutions come into mind:
-1-
You could also try to have the common functionality in a separate Trait.
-2-
I won't do the
new SecondController($container)
inside the constructor of the FirstController unless you need it at every controller-hit.
I like lazy loading, so it will load only when needed.
If your AddressController and OrderController has same parent class, than move these methods to parent:
class AddressContoller extends Controller {
public function test() {
$this->methodFromParent();
}
}
If not, create new object of that class and call method. Method must be public
class AddressContoller extends Controller {
public function test() {
$order = new OrderController();
$order->publicMethodInOrderClass();
}
}
If your OrderController wants to call a method foo from AccessController, you should think about moving foo somewhere else. That's an good indicator for wrong SRP
There are two possibilities
foo belongs to/is relevant for every Controller and has something to do with controlling: Just move it to the parent class.
foo is relevant to only a few classes: Move it to the class, it belongs to. This could be an helper class, some domain model class, or something else. Maybe you have to intruduce a new class to do this.
After a lot of reseach I finally manage to get a solution! Posting it here so if anyone in future might get help from it:
class FirstController
{
protected $container;
protected $db;
protected $view;
protected $second;
// constructor receives container instance
public function __construct(\Interop\Container\ContainerInterface $container) {
$this->second = new SecondController($container);
$this->container = $container;
$this->db = $this->container->db;
$this->view = $this->container->view;
}
public function LocalFunction(){
$this->second->otherFunction();
//call the functions in other classes as above
}
}
I've seen a few questions with really similar titles but they where irrelevant to my specific problem.
Basically, I want to access the variables from my core class in a class which extends core, but things seem to be quite complicated compared to other examples. I am using a MVC framework. I've simplified the code below to remove anything that was irrelevant.
index.php
// Load the core
include_once('core.php');
$core = new Core($uri, $curpath);
$core->loadController('property');
core.php
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once('controller/'.$name.'.php');
$controller = new $name();
}
}
property.php
class Property extends Core
{
function __construct()
{
print $this->curpath;
}
}
Printing $this->curpath just returns nothing. The variable has been set but it is empty.
If I print $this->curpath inside core.php it prints fine.
How can I access this variable?
You are doing it wrong tm
You should be utilizing an autoloader, instead of including files with each class manually. You should learn about spl_autoload_register() and and namespaces, and how to utilize both of them.
Do not generate output in the __construct() methods. That's an extremely bad practice
The variables are still there. That is not the problem. In PHP, when you extend a class, it does not inherit the constructor.
You do not understand how inheritance works. When you call method on instance of extended class it will not execute parent class's method , before calling extended class's methods. They get overwritten , not stacked.
Object variables should not be exposed. You are breaking the encapsulation. Instead og defining them as public you should use protected.
You should extend classes of they are different type same general thing. The extends in PHP means is-a. Which means that, when you write class Oak extends Tree, you mean that all the oaks are trees. The same rule would mean, that in your understanding all Property instances are just a special case of Core instances. Which they clearly ain't.
In OOP, we have principle. One of which is Liskov substitution principle (shorter explanation). And this is the thing your classes are violating.
The problem, I think, lies here:
If you consider a simple inheritance like this one:
class Dog{
public $color;
public function __construct($color){
$this->color = $color;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
}
}
//Create Dog:
$alfred = new Dog('brown');
//Create TrainedDog
$lassie = new TrainedDog('golden',array('fetch'));
In this example $alfred is a brown dog and $lassie is a golden dog. The two instances are separate from each other, the only thing they have in common is that they both have a property called $color.
If you want a variable that is available in all Dogs for example, you need a class variable:
class Dog{
public $color;
public static $numberOfLegs; //Class variable available in every instance of Dog.
public function __construct($color, $numberOfLegs){
$this->color = $color;
self::$numberOfLegs = $numberOfLegs;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
echo parent::$numberOfLegs;
}
}
This does not make much sense in many cases though, because if you have two instances of the parent class (in you're case Core), they also share the class variable.
Unless you can ensure that Core is instanciated only once, this approach will not work. If it does only exist once, you can just as well use constant variables to store the 2 properties.
If there exist multiple instances/objects of Core, I'd recommend using a composition (as suggested by Alvin Wong).
class Core{
//Just as you programmed it.
}
class Property{
private $core;
public function __construct($core){
$this->core = $core;
echo $core->curPath;
}
}
Try this
include_once('core.php');
$core = new Core('test', 'path');
$core->loadController('property');
class Property extends Core
{
function __construct($date)
{
print $date->curpath;
}
}
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once($name.'.php');
$controller = new $name($this);
}
}
How can I initialize class' base class by return value in construct? Let's say I have this as a base class:
class Base
{
public function Foo()
{
}
private $_var;
}
I also have this one static method from another class, which returns Base class:
class MyStaticClass
{
public static function Get()
{
return new Base();
}
}
and now I derive from base class it here:
class Derived extends Base
{
public function __construct()
{
// Here, how can I initialize Base class with
// object MyStaticClass returns? Something like
parent = MyStaticClass::Get(); // This doesn't obviously work..
}
}
Is there any solution / workaround to this?
Though it seems like an uncommon way of doing it, you probably mean this:
class Derived extends Base
{
public function __construct()
{
parent::__construct(MyStaticClass::Get());
}
}
I have not found a way to directly do that, but if you are willing to let go of class, you can accomplish this with javascript-style OOP. See my answer on https://stackoverflow.com/a/10468793/1369091
i've one stupid question.
I keep trying to write my framework, but ... i miss something.
I have one base class Base.class.php, with some functions.
When, i write another class SubBase.class.php, who extends Base, i trying to set one variable , who must use in Base class, in one static function (maybe).
Something like that
class Base {
public $vars;
public function GetA() {
return $this->vars;
}
}
public SubBase extends Base {
public function __construct() {
$this->vars = array();
}
}
But, i missing something ...
In role, my SubBase is subpage from my web, Base is printHTML class. I trying to set a title to my web, with my Base class, who set $this->vars in my SubBase class o.O
Please, tell me if i'm wrong, and let me know how to write this.
I wonna just write
<title> <?php echo Base::GetTitle(); ?> </title>
and show in.
Well, you should take a look at static properties and methods: http://php.net/manual/en/language.oop5.static.php
To accomplish what you want, you can try the following:
class Base {
//--------------------------------
// Declare static property
public static $title = '';
//--------------------------------
// Declare static method
public static function GetTitle() {
return self::$title;
}
}
public SubBase extends Base {
//--------------------------------
// Construct which overwrites
// Base::$title
public function __construct($newTitle){
self::$title = $newTitle;
}
}
//--------------------------------
// Instantiate your SubBase object
$subPage = new SubBase($newTitle = 'Welcome to my sub page');
//--------------------------------
// And in your HTML, use
<title> <?php echo SubBase::GetTitle(); ?> </title>
Note, that I used SubBase::GetTitle(); and not Base::GetTitle(); If you use Base::GetTitle(), you're output will be blank because you're using the value given at the Base Class. In my example, its:
public static $title = '';
However, when you instantiate your SubBase class, you provide a "$newTitle" parameter, which then overrides the blank value.
Ideally, this should work. Still, I recommend you learn more about the use of static properties and methods.
Hope this helps.
I have a helper called Zend_View_Helper_FormVars that's used by one of my modules.
I also have a common helper in application/common/helpers/GeneralFunctions.php
I'm trying to call a function from Zend_View_Helper_FormVars that's in GeneralFunctions.php.
Here is the short version of Zend_View_Helper_FormVars:
class Zend_View_Helper_FormVars
{
public $reqFieldVisual='<span class="req">*</span>';
public $roles=array('admin'=>'admin', 'user'=>'user');
public $paymentMethods=array('1'=>'Check', '2'=>'Credit Card',
'3'=>'Cash', '4'=>'Other');
public function formVars(){
$this->baseUrl=Zend_Controller_Front::getInstance()->getBaseUrl();
return $this;
}
public function mkCategoryCodeSelectGroup($codeTypeArr=array(),
$codesArr=array()) {
$html='';
$html.=Zend_View_Helper_GeneralFunctions::generalFunctions()->progressMeter();
return $html;
}
}
Here is the code in GeneralFunctions.php:
class Zend_View_Helper_GeneralFunctions
{
public function generalFunctions(){
$this->baseUrl=Zend_Controller_Front::getInstance()->getBaseUrl();
return $this;
}
public function progressMeter() {
$html='';
$html.='<span id="progressWrapper">';
$html.='<span id="progressMeter"></span>';
$html.='</span>';
$html.='';
return $html;
}
}
Also, forgot to mention that I have the GeneralFunctions helper auto loaded in the Bootstrap like this and it's available to all my modules already:
$view->addHelperPath(APPLICATION_PATH .'/common/helpers', 'View_Helper');
Here is what I tried, but am getting an error:
// application/Bootstrap.php ----------->
function _initViewHelpers() {
// add a helper for use for all modules
$view->addHelperPath(APPLICATION_PATH .'/Common/Helper', 'Common_Helper');
}
//-------------------->
// application/common/helpers/General.php ----------->
class Zend_View_Helper_General extends Zend_View_Helper_Abstract
{
public function general(){
return $this;
}
public function test(){
return 'test 123';
}
}
//-------------------->
// application/modules/dashboard/views/helpers/DashboardHelper.php ----------->
class Zend_View_Helper_DashboardHelper extends Common_Helper_General
{
public function dashboardHelper(){
return $this;
}
public function dashboardTest(){
return 'from dashboard';
}
}
//-------------------->
// application/modules/dashboard/views/scripts/index/index.phtml ----------->
echo $this->dashboardHelper()->test();
//-------------------->
Error message I get:
Fatal error: Class 'Common_Helper_General' not found in /Applications/MAMP/htdocs/mysite/application/modules/dashboard/views/helpers/DashboardHelper.php on line 2
It's actually really simple to call another View Helper.
Make sure that your view helper extends Zend_View_Helper_Abstract, so that it has access to the $view. Then you may simply call helpers as you would from a view, i.e.
$this->view->generalFunctions()->progressMeter();
Based on your example above:
<?php
class Zend_View_Helper_FormVars extends Zend_View_Helper_Abstract {
/* ... */
public function mkCategoryCodeSelectGroup($codeTypeArr=array(),
$codesArr=array()) {
$html='';
$html. $this->view->generalFunctions()->progressMeter();
return $html;
}
}
You possibly haven't configured your autoloader to load classes from the application/common/helpers/ folder.
See Zend_Application_Module_Autoloader for default paths. You should add your new folder to this.
I see several problems with your provided code.
You are attempting to call Zend_View_Helper_GeneralFunctions::generalFunctions() as a static method when it is declared as a class method (ie you have to instantiate an instance of the class to use it) by reason of your omission of the static keyword.
If you in fact want to use generalFunctions() as a static method and correct this then you will need to either make baseUrl a static property or you will have to instantiate an instance of the class and then return that instance.
The idea of using your GeneralFunctions class as a container for static methods that are called directly is really a symptom of deeper problems and is rightly labeled a code smell. If you think that I'm lying take a look at the high priority items for the Zend Framework 2.0 (hint: it involves removing all static methods from the framework). Or you can always ask SO what they think of static methods :-).
Looking at your given class name for the general functions class Zend_View_Helper_GeneralFunctions and given the current scenario where you are trying to use the GeneralFunctions helper inside another helper, I would surmise that you really need to do one of two things.
You need to have every helper class subclass the GeneralFunctions class so that all of your helpers have these functions available. Basically, ask yourself if your helpers all start out life as GeneralFunction helpers with extended functionality beyond. This solution uses inheritance to solve your problem.
Every view helper should contain an instance of the View object being acted upon. Therefore in theory you should be able to access any other view helper via the magic __call method (I think there is also an explicit method but I always use the magic method). It might look like so in your scenario:
public function mkCategoryCodeSelectGroup($codeTypeArr=array(), $codesArr=array())
{
$html='';
$html.= $this->generalFunctions()->progressMeter();
return $html;
}
In this scenario the __call method would load the GeneralFunctions helper and would then would call the progressMeter() method from the GeneralFunctions helper.
Now your GeneralFunctions helper class would probably look like this:
class Zend_View_Helper_GeneralFunctions
{
public function __construct()
{
$this->baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl();
}
public function progressMeter() {
$html='';
$html.='<span id="progressWrapper">';
$html.='<span id="progressMeter"></span>';
$html.='</span>';
$html.='';
return $html;
}
}
You are calling your class without instantiating it.
Your generalFunctions() function uses the $this pointer, which won't work; also it isn't a static method.
One option is set progress meter to be a static function and call it directly like this:
Zend_View_Helper_GeneralFunctions::progressMeter();
Another option is to instantiate your class first.