i have this class
class Product {
public $name;
private $price2;
protected $number;
function getNmae() {
return $this->name;
}
function getPrice() {
return $this->price2;
}
function getNumber() {
return $this->number;
}
}
and here I can use private price without any problem?
<?php
include 'oop_test.php';
class Banana extends Product {
}
$ba = new Banana();
echo $ba->price2 = 2000;
?>
the result like this:
I cannot understand how could I assign value to private variable ?
Looks like you've created a property on-the-fly in this case. A reduced sample shows this:
<?php
class Product {
private $price2;
function getPrice() {
return $this->price2;
}
}
class Banana extends Product {}
$ba = new Banana();
$ba->price2 = 2000;
echo 'On the fly property: ' . $ba->price2;
echo 'Private property: ' . $ba->getPrice();
That code prints 2000 for the property price2, but nothing is returned from getPrice - so you haven't really written the property price2 on the Product class, but created a new one within the Banana class.
The "original" property from the Product class is not involved here, as it is a private property and thus not available in the Banana class after all.
Actually the display of 2000 does not mean that the parent class value is set.
Your statement only creates a new variable for the class itself, not for the parent class because the price2 is not declared as protected / public.
It explains why the system does not throw an error in your case
Recap:
public scope to make that property/method available from anywhere, other classes and instances of the object.
private scope when you want your property/method to be visible in its own class only.
protected scope when you want to make your property/method visible in all classes that extend current class including the parent class
Try create a method (say setPrice) to set the price2 in the parent class if you need to set a value for this private variable
<?php
class Product {
private $price2;
function setPrice($a) {
$this->price2 = $a;
}
function getPrice() {
return $this->price2;
}
}
class Banana extends Product {
}
$ba = new Banana();
//$ba->price2 = 2000;
/*The above will not throw an error even executed
because it is creating a property within
the banana class*/
$ba->setPrice(2001);
echo $ba->getPrice();
/*The above is for setting / getting
the price2 private variable
in the parent class-just for illustration*/
?>
Related
I'm aware of a pattern for adding a static counter to a class to count the number of instances of that class
class Vehicle
{
private static $_count=0;
public static function getCount() {
return self::$_count;
}
public function __construct()
{
self::$_count++;
}
}
What I would like to do is to add a couple of subclasses to Vehicle and count instances of those independently
class Bike extends Vehicle
{
...
}
class Car extends Vehicle
{
...
}
So calling Bike::getCount() and Car::getCount() would get the count of the number of Bikes and Cars respectively
Is this possible without
repeating code in the subclasses?
setting up some kind of counting array keyed by class name in the superclass?
You can keep an array of counts in the parent class rather than just a single integer, indexed using static:class. This will reference the class name of the current instance, unlike self::, which always references the class in which it's being used.
class Vehicle
{
private static $counts = [];
public static function getCount()
{
return self::$counts[static::class];
}
public function __construct()
{
// Using a reference here to avoid undefined-index notices
$target =& self::$counts[static::class];
$target++;
}
}
class Bike extends Vehicle {}
new Bike;
var_dump(Bike::getCount());
// int(1)
Full demo here: https://3v4l.org/Qibd7
I'd also agree with #u_mulder's comment that this is a bit of an unusual pattern. A class definition should only be concerned with attributes of a single instance, and not store global state. Maintaining a collection of instances (even in a plain PHP array) would mean that you could count them independently. But that's up to you.
A lot depends on where you define the count and how you access it. If you have 1 count in the base class, then there is only 1 count. If you have a count in each class, then you need to be aware of how to access the right value. Using self or static is discussed more What is the difference between self::$bar and static::$bar in PHP?
class Vehicle
{
protected static $_count=0;
public static function getCount() {
return static::$_count;
}
public function __construct($type, $year)
{
// Access the count in the current class (Bike or Car).
static::$_count++;
// Access the count in this class
self::$_count++;
}
}
class Bike extends Vehicle
{
protected static $_count=0;
}
class Car extends Vehicle
{
protected static $_count=0;
}
This has both, and in the constructor, it increments them both. This means there is a total of all vehicles and of each type...
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Car("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Bike("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
gives (not very clear though)...
Vehicle::getCount()=0
Car::getCount()=0
Bike::getCount()=0
Vehicle::getCount()=1
Car::getCount()=1
Bike::getCount()=0
Vehicle::getCount()=2
Car::getCount()=1
Bike::getCount()=1
I have two classes (Model and User) but I have a problem so I have tried to explain it in a simple example :
class person
{
protected static $todo ="nothing";
public function __construct(){}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
protected static $todo ="studing";
}
$s = new student();
$s->get_what_todo(); // this will show the word (nothing)
//but I want to show the word (studing)
Please give me a solution but without writing any function in the student class I only want to make declarations there :) and thank you :)
The principle is called "late static binding", and was introduced in PHP 5.3.0; with the self keyword to access the property defined in the calling class within the inheritance tree, or static to access the property defined in the child class within that inheritance tree.
class person
{
protected static $todo ="nothing";
public function __construct(){}
public function get_what_todo()
{
echo static::$todo; // change self:: to static::
}
}
class student extends person
{
protected static $todo ="studying";
}
class teacher extends person
{
protected static $todo ="marking";
}
class guest extends person
{
}
$s = new student();
$s->get_what_todo(); // this will show the "studying" from the instantiated child class
$t = new teacher();
$t->get_what_todo(); // this will show the "marking" from the instantiated child class
$g = new guest();
$g->get_what_todo(); // this will show the "nothing" from the parent class,
// because $todo is not overriden in the child class
The reliable way to override a static variable is to do it by redeclaring it. Some people may suggest modifying it in the construct method, but I don't think that's reliable.
It won't reflect the changes until the class is constructed at least once. And of course, in class methods, don't forget to call the static variable using "static::" instead of "self::" when you want to always access the overridden variable.
Here's an example of what I mean:
The class Foo is the base class, the class Bar is changing the variable inside its constructor, and the class Baz is overriding the variable in its declaration.
class Foo
{
public static $a = "base";
}
class Bar extends Foo
{
function __construct()
{
self::$a = "overridden";
}
}
class Baz extends Foo
{
public static $a = "overridden";
}
echo 'Foo: ' . Foo::$a . '<br>';
echo 'Bar: ' . Bar::$a . '<br>';
echo 'Baz: ' . Baz::$a . '<br>';
new Bar();
echo 'Bar after instantiation: ' . Bar::$a;
This is the output from phptester.net
Foo: base
Bar: base
Baz: overridden
Bar after instantiation: overridden
As you can see, Bar's way of changing the variable isn't taking effect until after the constructor is called at least once.
EDIT: However, there is another way to edit a variable permanently and reliably: do it after the class declaration. This is especially handy if you only need to modify a variable and not completely override it, like for example an array. It feels a bit dirty, but in theory should work everytime.
class Foo
{
public static $a = [
'a' => 'a'
];
}
class Bar extends Foo
{
public static $a;
}
Bar::$a = Foo::$a;
Bar::$a['b'] = 'b';
echo 'Foo: ' . print_r(Foo::$a, true) . '<br>';
echo 'Bar: ' . print_r(Bar::$a, true) . '<br>';
This is the output from phptester.net
Foo: Array ( [a] => a )
Bar: Array ( [a] => a [b] => b )
EDIT 2: This last method also gets picked up by ReflectionClass::getStaticPropertyValue in my tests.
you can try set variable in construction
class person
{
protected static $todo = null;
public function __construct(){
self::$todo = "nothing";
}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
public function __construct() {
self::$todo = "student";
}
}
$s = new student();
$s->get_what_todo();
you can try set parent variable in construction
class person
{
protected static $todo = null;
public function __construct(){
self::$todo = "nothing";
}
public function get_what_todo()
{
echo self::$todo;
}
}
class student extends person
{
public function __construct() {
parent::$todo = "student";
}
}
$s = new student();
$s->get_what_todo();
I found something strange in the process of PHP object inheritance.
I can call NON static parent method from a subclass.
I cannot find any information about the possibility of this happening. Moreover, the PHP interpreter does not display errors.
Why it is possible?
Is this normal PHP feature?
Is it bad practice?
Here you are a code that you can use to test it.
<?php
class SomeParent {
// we will initialize this variable right here
private $greeting = 'Hello';
// we will initialize this in the constructor
private $bye ;
public function __construct()
{
$this->bye = 'Goodbye';
}
public function sayHi()
{
print $this->greeting;
}
public function sayBye()
{
print $this->bye;
}
public static function saySomething()
{
print 'How are you?';
}
}
class SomeChild extends SomeParent {
public function __construct()
{
parent::__construct();
}
/**
* Let's see what happens when we call a parent method
* from an overloaded method of its child
*/
public function sayHi()
{
parent::sayHi();
}
/**
* Let's call a parent method from an overloaded method of
* its child. But this time we will try to see if it will
* work for parent properties that were initialized in the
* parent's constructor
*/
public function sayBye()
{
parent::sayBye();
}
/**
* Let's see if calling static methods on the parent works
* from an overloaded static method of its child.
*/
public static function saySomething()
{
parent::saySomething();
}
}
$obj = new SomeChild();
$obj->sayHi(); // prints Hello
$obj->sayBye(); // prints Goodbye
SomeChild::saySomething(); // prints How are you?
That's the way, methods of a parent class are called from subclasses in PHP. If you override a method, you often need a way to include the functionality of the parent's method. PHP provides this via the parent keyword. See http://www.php.net/manual/en/keyword.parent.php.
This is a default functionality of PHP, In this way even after overriding the parent method, you can still add its existing functionality in child method.
ex-
class vehicle {
function horn()
{
echo "poo poo";
}
}
class audi extends vehicle {
function horn()
{
parent::horn();
echo "pee pee";
}
}
$newvehicle =new audi();
$newvehicle->horn(); // this will print out "poo poo pee pee"
I am trying to write a PHP class in which I change the visibility of a few methods from protected to public. I believe I remember you can do this in C++, but I did a few searches and I am not coming up with anything for that in PHP. Does anyone know if this is even possible in PHP?
For example, suppose this class:
class ABC {
protected function foo() {
// Do something
}
}
class DEG extends ABC {
// can I make foo public now?
}
You can change the visibility of members when deriving from a base class like this:
class Base
{
protected function foo() {}
}
class Derived extends Base
{
public function foo() { return parent::foo(); }
}
You can also do the same with properties (redefine a protected property as public).
However, be aware that if the base property is private then you will not actually increase its accessibility but rather declare a new property with the same name. This is not an issue with functions, as if you tried to call a private base method you would immediately get a runtime error.
You can overwrite a method in a derived class to highten it´s visibility (e.g. protected->public). Make the new function return it´s parent.
You cannot do so to limit it´s visibility (e.g. public->protected), but you can implement a method that checks the backtrace for the caller and thwors an exception if it´s a foreign class.
You can always use the reflection API to do all kinds of changes to the visibility.
Yes, it can be done. Quoting from PHP manual..
The visibility of a property or method can be defined by prefixing the
declaration with the keywords public, protected or private. Class
members declared public can be accessed everywhere. Members declared
protected can be accessed only within the class itself and by
inherited and parent classes. Members declared as private may only be
accessed by the class that defines the member.
And the example from there as well..
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private
Edit : Yes, you can change visibility of public and protected members. Another example from PHP manual..
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// We can redeclare the public and protected method, but not private
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, Undefined
?>
I'm trying to wrap my head around something that I can't seem to figure out a solution for. In class A I have a property which is a multidimensional array. In class B which is instantiated within class A, I'd like to set an index value for the property from class A. I run into a wall where I have no idea how to iterate through the property to set the value for the index I'd need to. Here's a test example of what I mean:
<?php
class SomeClass
{
protected $class;
protected $book;
public function __construct()
{
$this->book["genre"]["title"] = "The Haunting";
}
public function SomeTest()
{
$this->class = new AnotherClass();
$this->class->AnotherTest();
}
}
class AnotherClass
{
protected function setBook()
{
$indexes = func_get_args();
$value = array_pop($indexes);
/**
* So now I have the indexes which lead to the array
* depth I'd like to set a value to, but where do I
* go from here?
*
*/
}
public function AnotherTest()
{
$this->setBook("something", "else", "1984");
}
}
$someclass = new SomeClass();
$someclass->SomeTest();
?>
I'm so lost on how to do what I'm thinking of.
initiate class Another with a parameter, pass initiator class!
class SomeClass{
public function SomeTest() {
$this->class = new AnotherClass($this);
$this->class->AnotherTest();
}
}
I use creator for these situations!
class AnotherClass{
function __contruct($creator){
$this->creator=$creator
}
function AnotherTest(){
$this->creator->setBook("something", "else", "1984");
}
In such a situation why you are not using inheritance? Your property is protected and I think it should not be accessible outside the class.
Hay you tried with inheritance?.
Thanks.