I'm building a PHP OOP MVC Framework for personal use.
I'd like to know if there's a way or the correct implementation of the following:
Being able to call a method from a "subclass" (not extended) to another "subclass". I mean...
I have a class that creates new objects for each subclass instead of using inheritance. Let's call it MainClass, and it has 3 "SubClasses" like this
class MainClass {
public $db;
public $forms;
public $pagination;
function __construct() {
$this->db = new class_db();
$this->forms = new class_forms();
$this->utils = new class_utils();
}
}
And the initialization which is
$MainClass = new MainClass();
I can do for example
$MainClass->utils->show_text("Hello World");
And works fine.
What I'd like to do is... within the $MainClass->utils->test() (Another test method), is to be able to access $MainClass->db without using global or $GLOBALS.
Is there any alternative way of achieving this? To be able to access $MainClass methods and submethods within another submethod (access db from utils and from the main page where MainClass is initialized)? How would it be? I want to be able to access al the submethods, like utils being able to access db and forms method. as well as the pages that are outside MainClass.
Thank you
If utils has to use db, you either have to pass the MainClass instance to utils, so it can call $this->myRefToMain->db, or pass the instance of db itself, so utils can call $this->db. Either way, it cannot (reasonably) crawl up the call stack to find the object that called it.
Object if your class class_utils can exists without MainClass. And its method test() should access some object db of class class_db. This means class_utils depends on class_db and you should inject object of class_db in constructor, for example:
class MainClass {
public $db;
public $forms;
public $pagination;
function __construct() {
$this->db = new class_db();
$this->forms = new class_forms();
$this->utils = new class_utils($this->db);
}
}
Related
I'm changing my class structure around to store common database methods in one class. Then extending it from a child class. This should cut down on code but also allows me to overwrite the parent methods when I need to.
I've done the following, for this example I've simplified to the basics compared to the original code which contains more classes.
class parent_object{
private $table_name;
public function all_records(){
$sql = "SELECT * FROM ".$this->table_name;
return $this->execute_sql($sql);
}
}
class child_object extends parent_object{
protected static $table_name="tbl_name";
public function __construct(){
parent::__construct(self::$table_name);
}
}
I want to call the all_records() statically to save myself creating a new object every time.
I'm stuck having to instantiate the child and then call the parent method
$child = new child_object();
$all = $child->all_records();
What I really want to be able to call the parent method statically:
$all = child_object::all_records();
I understand why I can't do it with my code, but would like some way that the child instantiates first then accesses the parent method.
I could write all_records() method in the child_object to instantiate itself and call the parent all_records() but that sort defeats the purpose of extending to cut down on code and the same methods in my child class.
I'm sure its quite simple or some new high level oop function can do it.
Thanks for your help.
The answer is relatively simple, you can turn all your properties into static properties, and then use static:: instead of self::.
http://php.net/manual/en/language.oop5.late-static-bindings.php
Solving your problem this way is considered a bad practice though. Good luck.
You could do something like this:
class child_object extends parent_object
{
protected static $table_name="tbl_name";
public static function factory()
{
return new child_object();
}
public function __construct()
{
parent::__construct(self::$table_name);
}
}
Then when you use it you just do:
$all = child_object::factory()->all_records();
Let's say I'm writing a PHP (>= 5.0) class that's meant to be a singleton. All of the docs I've read say to make the class constructor private so the class can't be directly instantiated.
So if I have something like this:
class SillyDB
{
private function __construct()
{
}
public static function getConnection()
{
}
}
Are there any cases where __construct() is called other than if I'm doing a
new SillyDB()
call inside the class itself?
And why am I allowed to instantiate SillyDB from inside itself at all?
A private constructor makes sure you cannot instanciate this class outside of itself.
So calling
$obj = new SillyDB();
would result in an error.
This technique is usually used when creating singleton classes.
This stone old comment in the manual describes it pretty well: http://www.php.net/manual/de/language.oop5.decon.php#80314
You have a static method inside the class that manages a single instance of the class which can be retreived through the method.
Calling the static function within that class may run the construct from within the class.
class SillyDB
{
private function __construct()
{
$db->connect();
}
public static function getConnection()
{
self::__construct();
}
}
Running
SillyDB::getConnection()
will run the __construct() method and connect you to the db
Are there any cases where __construct() is called other than if I'm
doing a new SillyDB() call inside the class itself?
No.
And why am I allowed to instantiate SillyDB from inside itself at all?
Why would you not be allowed to?
The better question would be what use is it for a constructor that can only be called from inside its own class?. That is useful when you want to ensure total control of how instances are created, for example when you implement a singleton.
__construct() would only be called if you called it from within a static method for the class containing the private constructor. So for your Singleton, you might have a method like so:
class DBConnection
{
private static $Connection = null;
public static function getConnection()
{
if(!isset(DBConnection::$Connection))
{
DBConnection::$Connection = new DBConnection();
}
return DBConnection::$Connection;
}
private function __construct()
{
}
}
$dbConnection = DBConnection::getConnection();
The reason you are able/would want to instantiate the class from within itself is so that you can check to make sure that only one instance exists at any given time. This is the whole point of a Singleton, after all. Using a Singleton for a database connection ensures that your application is not making a ton of DB connections at a time.
You are able to call it because scope is checked based on class rather than instance (i.e. an object is able to access the private and protected methods/properties of another instance of the same class without issue)
So I have a config.php file, wich is included on top of every page on the site before the tag. This file uses __autoload() to get all the php classes I use. Then, after autoloading them I assign the classes to variables like so...
$myclass = new Myclass();
$mysecondclass = new MySecondClass();
When I want to call $mysecondclass in $myclass, I get an undefined variable error. This is of course, because $mysecondclass was not defined before $myclass. How do I fix this where I can define all classes from any other class?
Thanks for any help:)
The best OOP approach would be to use a superObject with properties which are objects of other classes.
class Context{
var $myClass;
var $myOtherClass;
var $db;
//...
}
In your MyClass
class MyClass{
var $context;
public function __construct(&context){
$this->context = $context;
}
public function otherFunction(){
$this->context->myOtherClass->functionFromOtherClass();
}
}
You should be instantiating these classes using Factory method or any mechanism to manage objects.
To initialize MyClass you would implement something like this.
ObjectFactory::createObject('MyClass',$context);
$myclass is not Myclass it is an instance of Myclass (an object). Objects are not classes. If you want to use a new instance of MySecondClass inside of an instance of Myclass, just instantiate it in there.
Your question also deals with scope. You have created these two objects in the global scope. They are not automatically accessible within one another. If you have some object which you will have only one instance of and which you want to be global and accessible by others, you can import it into their scope with the global keyword. However, this is not usually the best way to go about it. Instead, you may want to look up the Singleton Pattern. It gives you a way to ensure that a particular class is only instantiated one time and gives you a way to access the object that has been created as a result of that instantiation.
The registry pattern is also an easy way to access "global" object anywhere in your code.
You can Take a look at Zend_Registry : http://framework.zend.com/manual/en/zend.registry.using.html
$myclass = new Myclass();
$mysecondclass = new MySecondClass();
Zend_Registry::set('mysecondclass', $mysecondclass);
$myclass->doSomething();
class Myclass
{
public function doSomething()
{
// use $mysecondclass via the registry
Zend_Registry::get('mysecondclass')->methodFromSecondClass();
}
}
class MySecondClass
{
public function methodFromSecondClass()
{
return true;
}
}
According to how your classes works, think about extending them... Extending MyClass to MySecondClass automatically gives access to parent properties / functions.
MyClass
class MyClass{
function myFunction(){
// code here
}
}
MySecondClass
class MySecondClass extends MyClass{
function __construct(){
$this->myFunction();
}
}
I've been programming in PHP for several years and I've only just recently begun to look at object oriented code. Now I understand classes and such:
class Myclass {
public function __construct() {
}
}
and all that good stuff... I also understand creating functions and calling in my index.php:
$someVar = new Myclass;
One thing I've been trying to understand, being that i've recently looked at codeigniter and I like one thing about it and want to try and accomplish the same thing without actually using codeigniter.
in code igniter they have the variable $this appear to be their class variable. But by using that, you're able to call from multiple classes all at once.. such as:
$this->load->module(); which is in one class file..
$this->db->query(); which is in another class file.
I've searched google for the last few days trying to figure out how to do this same thing where each class would have the correlation between them all allowing me to run $this->class_name->function_name in my projects instead of creating a new variable for each class or for the sake of a clean index file, having every function in a single class file.
Any information (aside from buy this book - as that isn't an option for me) is greatly appreciated and I will thank you now (and will probably thank you again later just for good measure).
I've been reading you and Phil's comments. First off, you can't use $this on index.php. $this can only be used in the context of an object. So you could do,
$someVar = new Myclass;
...
$someVar->db->something();
...instead.
I'm not entirely sure what you mean by "read classes," but you can assign members to MyClass exactly as Phil indicates:
class MyClass {
private $inj;
function __construct(Injected $inj) {
$this->injected = $inj;
}
}
Note that the private $inj declaration is not mandatory, but skipping it is dangerous. Any non-declared members added are automatically public, and this can potentially screw with you if you rely on magical get. I would declare the properties you need.
Finally, you either need to include all class definitions you will use, use a function like load_class(), or use autoloading. If Injected above is not a declared class, you will get an error when trying to create one. load_class() almost certainly includes the class definition somehow.
The load and db references are class properties which are themselves other objects with public module() and query() methods respectively. For example
class MyClass
{
/**
* #var CI_DB
*/
private $db;
/**
* #var Loader
*/
private $load;
public function __construct(CI_DB $db, Loader $load)
{
$this->db = $db;
$this->load = $load;
// PHP also allows you to add arbitrary object properties
// that receive a "public" visibility
// Please note, this is not a good practice
$this->foo = new Foo;
}
public function someMethod()
{
$this->load->module();
$this->db->query();
// You can also use foo even though it is not defined
// in the class properties
$this->foo->something();
}
}
See http://www.php.net/manual/en/language.oop5.properties.php
Adding the foo property like we did is dangerous. Because it receives the public visibility, it may be altered externally to the class.
$class = new MyClass($db, $load);
$class->foo = new Bar;
$class->someMethod(); // will break if Bar does not contain a something() method
Is it a good idea to create a static member in a class object and call that member for specific function? like:
class Users
{
public static Login(strUsername, strPassword)
{
$objThis = new Users();
....
}
}
and call it like:
Users::Login('admin', 'admin');
or second method:
class Users
{
public Login(strUsername, strPassword)
{
//$objThis = new Users();
....
}
}
and call it like:
$objThis = new Users();
$objThis->Login('admin','admin');
These functions are used when
You don't want to allow, to create
instance of class from outside the
class, indirectly you want to make
constructor private or protected.
Or You want to allow only single instance of class for the whole request(one request). For. eg. Classes for Database, Document etc.
The first method can be useful if you want to restrict access to the class, and not allow it to be instantiated. For example:
class Users {
private function __construct($strUsername, $strPassword) {
// this class can now not be instantiated
// except within itself
}
public static Login($strUsername, $strPassword)
{
return new self($strUsername, $strPassword);
}
}
This forces users of your class to always use the static method to get a User object, which can be desirable if you always want to restrict how its used.
As always, it largely depends on what you want to do. static is like a tool, and you use it when it's the right tool for the job on hand.
Usually static methods should be avoided - they complicate API and refactoring. I using static methods only as alternative to class constructors when initialization may throw an exception (reading from file, etc) and for private utility methods.