PHP - OOP class extend - php

Been searching all around but still cannot find a solution for this problem.
My problem is that i got these snips of code(Examples):
Core file
class Core {
public $DB = null;
public $Handler = null;
function run() {
$this->DB = "somedatabase";
include_once('handler.php');
$this->Handler = new Handler;
$this->Handler->run();
}
}
This is the helper.php example
class Handler extends Core {
function run() {
echo "<pre>"; print_r($this); echo "</pre>"; die();
}
}
Even tho i defined the DB variable before i include the helper then it is still empty inside the helper class. It's defined yes but it's empty. Which means it properly doesn't share the same memory as the Core class.
Keep in mind that the Core class it self is instanced too.
-
Thanks for all suggestions
Edit
PhpMyCoder got it right. Thank you for the detailed and well written reply.
For over 2 years i been seeing PHP scopes as being the same or sorta the same as JavaScript's scope. Now i realize that if i extend my "Core" class i get all the methods and properties within it. But the values is private to my class and my class alone.
This is great. Finally i got it.

From what I gather here you are talking about public instance variables. They are performing as OOP would require. Each time you instantiate a class with
$core = new Core(); // or
$handler = new Handler();
Each of them gets a fresh space in memory to store their instance variables. Instance variables are unique to each instance of a class, as the name would suggest. So, two separate instances of Core and Handler do not share instance variables. However since Handler extends Core, two instances of Core are created. One instance is the one that I created on the first line. The other is created so that Handler can extend it on the second line. These two instances of Core are not the same object. To have the same values for Core across all core objects you will need to use static (class) variables.
class Core {
public static $hello = 'World';
}
var_dump(Core::$hello); //string('Word')
In my example, $hello will always be available to everyone by accessing it with the scope resolution operator, ::. So Handler could access it with either Core::$hello or parent::$hello. If you wanted to only expose this static variable to Core and its subclasses, then you would need to make it protected and access it from within Core with self::$hello and from its subclasses with parent::$hello.
class Core {
protected static $hello = 'World';
public function sayHello() {
echo 'Hello '.self::$hello; //from within Core, access with `self`
}
}
class Handler extends Core {
public function myParentSays() {
echo 'My parent says: Hello '.parent::$hello;
}
}
$core = new Core();
$core->sayHello(); // 'Hello World'
$handler = new Handler();
$handler->myParentSays(); // 'My parent says: Hello World'
Check the PHP docs for more on the static keyword and the scope resolution operator.
EDIT
I believe your confusion lies in a misunderstanding of how inheritance works in OOP so let me give you a little real-world-ish example. Let's say you create a class for employees called Employee. This class has a public instance variable (that is, one that can be accessed with ->) for the name of the person. In PHP this would be:
class Employee {
public $name;
public __construct($name) {
$this->name = $name;
}
}
Now let's create a new employee:
$tim = new Employee('Tim');
Let's say that we need a new class, Intern, that should subclass Employee. That should be easy enough:
class Intern extends Employee {
public function makeCoffee(Employee $receiver) {}
}
If we create a new intern now, should his name be Time just because we have already created another employee named Tim? No. That doesn't make sense.
$intern = new Intern();
var_dump($intern->name); //string(0) ""
Now say that setting the name was some complicated and arduous process and we'd rather not have to code it again. With a little modification to our Intern class we can leave the name setting to its superclass, Employee.
class Intern {
public function __construct($name) {
parent::__construct($name);
}
public function makeCoffee(Employee $receiver) {}
}
Now we can create a new intern and set his or her name. Notice how the other Employee keeps his name.
$intern = new Intern('Something Forgettable');
var_dump($intern->name); // string(21) "Something Forgettable"
var_dump($employee->name); // string(3) "Tim"
Now why is this? In OOP, a subclass/superclass is an "is a" relationship. The Intern "is an" Employee. The Intern has all the same properties and methods as an Employee but because each Intern and Employee are distinct they have their own values for these properties.
With this in mind, I suggest you rethink your strategy for your classes. Does it really make sense that Handler is a Core? Does it make sense that MainController is a Handler?

Classes don't share memory unless you pass a reference to them. When you make an instance of a class (an object), it is unique. You could have:
$a = new Core();
$b = new Core();
$a->var1 = 'foo';
$b->var1 = 'bar';
echo $a->var1; // 'foo'
echo $b->var1; // 'bar'
The same holds for extending a class. It doesn't explicitly share the values of the fields, it just shares their existence/visibility.
To share the value, you would do something more like this:
$a = new Core();
$b = new Core();
$c = 'foo';
$a->var1 = &$c;
$b->var1 = &$c;
echo $a->var1; // 'foo'
$b->var1 = 'bar';
echo $a->var1; // 'bar'
$c = 'baz';
echo $a->var1; // 'baz'

Variables are only set on objects (class instances). Don't confuse classes with objects.
If you want to have variables bound to classes, use the static keyword:
class Core {
public static $static = 'abc';
public $instance = 'xyz';
}
Core::$static = 'x';
$core = new Core();
$core->instance = 'a';

In PHP, classes are extended, not objects. This is class:
class SomeClass{
// ...
}
And this is object:
$object = new SomeClass();
So, when your are extending some class, all its protected/public properties are become available to child class.

Related

Passing an object between different classes?

I've always passed data manually between different classes. So for example I had some data produced by one class:
$someData = $Object->someMethod();
$moreData = $Object2->anotherMethod($someData);
But it feels clunky to me and it results in messy code that gets complicated. Especially if there are multiple different kinds of data passed around multiple classes.
So instead of doing that I've decided I will create a class DataContainer that groups every variable related to the process and then I will just pass this object around different classes. As it passes the processing pipeline, it will gather more and more data until almost every of its field is set to some value.
So for example I have a pipeline of processing data that gets modified by 4 different classes - instead of passing the data by value I will pass it by reference:
$myObject = $class1->method1(); // this class returns the DataContainer object
$class2->method2($myObject);
$class3->method3($myObject);
$class4->method4($myObject);
Is it considered a better choice? Or is there something better?
Keep in mind to make your code SOLID. (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
In your case, you can create in the constructor of class2 a reference.
For example:
<?php
class Class1
{
private $class2;
public __construct(Class2 $class2)
{
$this->class2 = $class2;
}
public function CallMethodOfClass2()
{
$value = $this->class2->GetMethod();
$propertyValue = $this->class2->public_property;
}
}
?>
Or when your Class2 cant exists without Class1, make in the constructor of Class1 a new instance of Class2 like this:
<?php
class Class1
{
private $class2;
public __construct()
{
$this->class2 = new Class2();
}
public function CallMethodOfClass2()
{
$value = $this->class2->GetMethod();
$propertyValue = $this->class2->public_property;
}
}
?>

OO PHP Accessing public variable from another class

I have a class like the following:
class game {
public $db;
public $check;
public $lang;
public function __construct() {
$this->check = new check();
$this->lang = DEFAULT_LANG;
if (isset($_GET['lang']) && !$this->check->isEmpty($_GET['lang']))
$this->lang = $_GET['lang'];
}
}
As you can see I have a public variable $lang that is also defined via the contructor.
The proble is that I want to access the result of this variable from other classes that are not directly related to this class, since I don't want to redeclare it for each different class.
So for example how can I call the result of that variable from another class, lets call it class Check ?
if you mark the public $lang; as static:
public static $lang;
you can access it via game::$lang;
if not static, you need to make an instance of game and directly access it:
$game = new game;
$game->lang;
static call inside of (current) class:
self::$lang;
late static bound call (to inherited static variable):
static::$lang;
call from child class to parent:
parent::$lang;
normal call inside of an instance (instance is when you use new Obj();):
$this->lang;
BTW:
variables defined by define('DEFAULT_LANG', 'en_EN'); are GLOBAL scope, mean, can access everywhere!
<?php
define('TEST', 'xxx');
class game {
public function __construct() {
echo TEST;
}
}
//prints 'xxx'
new game;
you can make it static variable, so you will be able to call it anytime anywhere, the diff is that instead of
$this->lang;
when editing it(Works inside class game only) you do :
self::$lang;
and when you call/edit it (Works everywhere) from anther class you do :
game::$lang
the idea of static class is that its exist only in one instance, so only one $lang exist in your program. but there is no need to load the whole class to get acsess to it.
How can I call the result of that variable from another class, lets call it class Check?
A variable doesn't have a result. If you mean to retrieve the state of that variable on a specific object $obj of class game then you can simply do:
$obj->lang
On a side note if $lang is publicly only read only you should protect it by defining it private or protected and create a getter method instead.
If you mean that you want to use the same variable name in another class I'd suggest you to consider inheritance:
class Check extends game { /* now Check has $lang */ }
but the variable of the two objects will be different.
Since the property is public, you can access it from outside the class as $objInstance->property. It doesn't matter if you're calling it from a function, procedural script, in another object. As long as you have the instance, you can call it's public property. Ex:
function foo($c) {
echo $c->lang;
}
foo($check);
Also, some advice on working with objects and such: It's considered better code if you don't create instances of objects in the other objects, but rather pass them in someway (either a setter method or through the constructor). This keeps the classes loosely coupled and results in code that is more reusable and easier to test. So:
class Game
{
...
public function __construct($check, $defaultLang, $get) {
$this->check = $check;
$this->lang = $defaultLang;
if (isset($get['lang']) && !$this->check->isEmpty($get['lang']))
$this->lang = $get['lang'];
}
...
$game = new Game(new Check(), DEFAULT_LANG, $_GET);
echo $game->check;
The first half of this article is an accessible explanation of what is known as Dependency Injection.

PHP5 member visibility

Could someone explain me, why is it possible to do the following in PHP, but, for example, not in C# or Java:
Class A {
protected $a = 'Howdy!';
}
Class B extends A {
public function howdy() {
$created = new A();
echo $created->a; <----- This is legal due to per-class visibility
}
}
$b = new B();
echo $b->howdy(); <----- Hence, no fatal error here
This behavior seems to be specified here, but I can't understand the fundamental reason behind this (to my mind, one can't simply implement the per-class visibility instead of the per-instance one without having a strong reason for that).
The reason it doesn't work is, as you specified, PHP implements access control on a class level, where other languages use an instance level approach.
Why is it useful? It allows your classes to operate on other instances of itself without exposing its private data. Let's take a simple value-object example:
class Int {
protected $value = 0;
public function __construct($value) {
$this->value = (int) $value;
}
public function add(Int $new) {
return new Int($new->value + $this->value);
}
}
$a = new Int(1);
$b = new Int(2);
$c = $a->add($b);
This lets you keep protected info encapsulated, yet still work with it across instances...
There are pros and cons to both approaches...
That is also possible in C# (and Java for that matter).
class A // declare new class type B
{
protected string a = "Howdy!"; // that has a protected member called `a`
}
class B : A // declare new type B which extends type A
{
public void howdy()
{
A created = new A();
Console.WriteLine(created.a); // no problem accessing a b/c B extends A
}
}
B bInst = new B(); // create a new instance of type B
bInst.howdy(); // invoke it's public method howdy()
Basically what is going on is this:
class A contains a protected member called a which means it is visible in the scope of classes which extend A (in our case class B)
class B extend a so it has access to it's protected members (in our case to a)
It is possible to do in both C# and Java as well. protected means the variable is accessible from any subclass of A. B is a subclass of A, hence it can access the variable. There's no magic here.
The page you linked to has a section titled "Visibility from other objects" which states that:
Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.
It wouldn't work if you'd done this:
$b = new B();
echo $b->a;
In your example, you're not accessing the $a member direct from B(). You're accessing it from an A() object that happens to have been instantiated from inside B().

Calling a Class function without using $this->function_name() -- PHP --

So I have this class:
class A{
public function do_a(){ return 'a_done';};
public function do_b(){ return 'b_done';};
}
So I require the php file and create an instance of the class:
require_once("A_class.php");
$System = new A();
require_once("user_calls.php"); //here I import the user file with the function calls.
user_calls.php contents:
echo 'this was the result of '.$System->do_a();
echo 'this was the result of '.$System->do_b();
So, that does work, but I don't want the user to have to use $System->do_a();, but only do_a();.
Any solutions?
EDIT: I also want to limit the functions the user could call in the user_calls.php file, to basic native php functions and those in class A.
DISCLAIMER: While this code works, and does what you requested, that doesn't mean that I advocate coding like this. It's very hard to follow for other developers (and maybe even you in the future...), and it also makes use of eval(), which is almost always A Bad Thing(tm). That said, here you go:
<?php
class A {
public function do_a() {
return __METHOD__;
}
public function do_b() {
return __METHOD__;
}
}
$aRef = new ReflectionClass('A');
$aPublicMethods = $aRef->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($aPublicMethods as $method) {
$php = <<<PHP
function {$method->name}() {
global \$System;
return \$System->{$method->name}();
}
PHP;
eval($php);
}
$System = new A();
echo 'this was the result of ' . do_a();
echo 'this was the result of ' . do_b();
Please also note that if your methods use arguments, things get even more hairy. Also, if you name any of your methods the same as a function in the global namespace (ex. substr()), this will attempt to redefine them, and you'll probably get a Fatal Error.
Methods of a class are either instance methods (they act on a particular instance of a class defined by $this) or they are class methods (They aren't tied to any one particular instance of a class, but provide services that fall within the remit of the class.
An instance method is defined as follows:
public function foo()
{
}
whereas a class method is defined with the STATIC keyword.
static public function bar()
{
}
In the instance method you can use $this to get access to the state of the instance on which the method was called. This is not available in the class method because it's not tied to any one instance. It can access other members of the class (provided they're not tied to an instance) with the self keyword though.
Instance methods are called as follows:
$a = new ObjType ()
$output = $a -> foo ();
Class methods are called as follows:
$output = ObjType::bar ();
No matter which approach you use you either have to provide an instance (for instance methods) or a class (for class methods) to call the method. Calling just foo() or bar() will not work.
You'll have to use a closure. Note that it's calling directly from the class definition, not the object:
class test {
function method() {
echo 'method was called';
}
}
$method = function(){call_user_func('test::method');};
$method();
$method();
$method();
//output:
//method was calledmethod was calledmethod was called
To call the method from the object, rather than the class, you'll have to pass the object into the closure:
class test {
var $count = 0;
function method() {
$this->count++;
echo $this->count . "|<br />";
}
}
$obj = new test;
$obj2 = new test;
$method = function($object){call_user_func(array($object, 'method'));};
$method($obj);
$method($obj);
$method($obj);
$method($obj2);
//output:
//1|
//2|
//3|
//1|
But that's not any prettier or simpler, is it?
If you don't want to clutter up your page, just name the object something short:
$pco = new page_controller_object_with_a_long_name_that_is_annoying;
$pco->do_a();
$pco->do_b();
//etc.
Moving it outside the class as suggested by #LucM sounds the easiest way.

PHP constructors and static functions

I'm a bit confused on how constructors work in PHP.
I have a class with a constructor which gets called when I instantiate a new object.
$foo = new Foo($args);
__construct($params) is called in the class Foo and it executes the appropriate initialization code.
However when I use the class to call a static function, the constructor is called again.
$bar = Foo::some_function(); //runs the constructor from Foo
This causes the constructor to execute, running the object initialization code that I intended only for when I create a new Foo object.
Am I missing the point of how constructors work? Or is there a way to prevent __construct() from executing when I use the class to make static function calls?
Should I use a "factory" function instead to do the object initialization? If so, what's the point of the constructor then?
::EDIT::
I have a form where users can upload photos to an album (create_photo.php) and an area where they can view the album (view_photos.php). Upon form submit:
$photo = new Photo($_FILES['photo'], $_POST['arg1'], ect..);
The Photo constructor creates and saves the photo. However in view_photo.php, when I call:
$photo = Photo::find_by_id($_POST['id']) //user-defined function to query database
This is causing Photo's constructor to run!
I see nothing that replicates your question.
See Demo: http://codepad.org/h2TMPYUV
Code:
class Foo {
function __construct(){
echo 'hi!';
}
static function bar(){
return 'there';
}
}
echo Foo::bar(); //output: "there"
Assumption
PHP 5.x
Different goals, different path
create a new instance of a class (object)
class myClassA
{
public $lv;
public function __construct($par)
{
echo "Inside the constructor\n";
$this->lv = $par;
}
}
$a = new myClassA(11);
$b = new myClassA(63);
because we create a new object PHP calls:
__construct($par);
of the new object, so:
$a->lv == 11
$b->lv == 63
use a function of a class
class myClassB
{
public static $sv;
public static function psf($par)
{
self::$sv = $par;
}
}
myClassB::psf("Hello!");
$rf = &myClassB::$sv;
myClassB::psf("Hi.");
now $rf == "Hi."
function or variabiles must defined static to be accessed by ::, no object is created calling "psf", the "class variable" sv has only 1 instance inside the class.
use a singleton created by a Factory (myClassA is above)
class myClassC
{
private static $singleton;
public static function getInstance($par){
if(is_null(self::$singleton)){
self::$singleton = new myClassA($par);
}
return self::$singleton;
}
}
$g = myClassC::getInstance("gino");
echo "got G\n";
$p = myClassC::getInstance("pino");
echo "got P\n";
Using the factory (getInstance) the first time we construct a new object having $par set to gino.
Using the factory the second time $singleton has already a value that we return. No new object is created (no __construct is called, less memory & cpu is used).
The value of course is an object instanceOf myClassA and don't forget:
myClassC::$singleton->lv == "gino"
Pay attention to singletons:
What is so bad about singletons?
http://www.youtube.com/watch?v=-FRm3VPhseI
By my answer I don't want promote/demote singleton. Simply from the words in the question, I made this calc:
"static"+"__construct"="singleton"!
Here is my workaround:
I put method construct() in static class. Notice, it is different than __construct() which I use in regular classes.
Each class is in own file, so I lazy load that file on first use of class. This gives me event of first use of class.
spl_autoload_register(function($class) {
include_once './' . $class . '.php';
if (method_exists($class, 'construct')) {
$class::construct();
}
});
I define class properties as array in a static method and call them via the method. I'm not sure if it's the best solution or not but works great.
Example:
class Foo
{
private static construct_method()
{
return [
'one' => 1,
'two' => 2
];
}
public static any_method()
{
return self::construct_method()['one'] + self::construct_method()['two'];
}
}
echo Foo::any_method(); // 3

Categories