Use method of parent class when extending - php

Probably a silly question.. but how do I correctly use the methods of class Test in class Testb without overriding them?
<?php
class Test {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
<?php
class Testb extends Test {
public function __construct() {
parent::__construct($name);
}
}
<?php
include('test.php');
include('testb.php');
$a = new Test('John');
$b = new Testb('Batman');
echo $b->getName();

You need to give the Testb constructor a $name parameter too if you want to be able to initialize it with that argument. I modified your Testb class so that its constructor actually takes an argument. The way you currently have it, you should not be able to initialize your Testb class. I use the code as follows:
<?php
class Test {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
class Testb extends Test {
// I added the $name parameter to this constructor as well
// before it was blank.
public function __construct($name) {
parent::__construct($name);
}
}
$a = new Test('John');
$b = new Testb('Batman');
echo $a->getName();
echo $b->getName();
?>
Perhaps you do not have error reporting enabled? In any event, you can verify my results here: http://ideone.com/MHP2oX

Related

Creating dynamic class this pointer

I am noob in PHP because I am mostly do .NET/Java. In code base I am working, I have,
class SomeOtherBaseClass{
public $prop2;
public function __construct(string $prop3)
{
$this->prop2 = $prop3;
}
public function __toString()
{
return $this->prop2 . ' '. $this->prop2;
}
}
class SomeClass
{
public function __toString()
{
return $this->prop1 . ' '. $this->prop1;
}
public $prop1;
public function someMethod() : SomeOtherBaseClass
{
return $this->createClass();
}
public function __construct()
{
$this->prop1 = 'foo';
}
private function createClass(
): SomeOtherBaseClass {
return new class(
$this->prop1
) extends SomeOtherBaseClass {
};
}
}
$class = new SomeClass();
echo $class;
echo $class->someMethod();
Why I am getting error that prop1 not found. Clearly createClass function is part of SomeClass which have prop1. Why I cannot access prop1 inside createClass?
It's because $prop1 has no value or meaning.
You can add a __construct() function to resolve your issue:
public function __construct()
{
$this->prop1 = 'foo';
}
now when you call this class (e.g. $foo = new SomeClass();):
$prop1 has a value of foo which can be used in your functions:
public function echoProp()
{
echo $this->prop1; # will output foo
}
Note: This is just an explanation answer - not a copy/paste solution - but the principles are all here for you to use in your code.
Let me know if this wasn't what you were looking for :)
Edit:
if prop1 exists in SomeOtherClass, when you construct you can do
public function __construct()
{
$this->class = new SomeClass();
$this->prop1 = $this->class->prop1;
}

Switch visibility in php if parameter

I'm wondering if its possible to switch the visibility in PHP. Let me demonstrate:
class One {
function __construct($id){
if(is_numeric($id)){
//Test function becomes public instead of private.
}
}
private function test(){
//This is a private function but if $id is numeric this is a public function
}
}
Is such thing even possible?
I would use an abstract class with two implementing classes: One for numeric and one for non-numeric:
abstract class One {
static function generate($id) {
return is_numeric($id) ? new OneNumeric($id) : new OneNonNumeric($id);
}
private function __construct($id) {
$this->id = $id;
}
}
class OneNumeric extends One {
private function test() {
}
}
class OneNonNumeric extends One {
public function test() {
}
}
$numeric = One::generate(5);
$non_numeric = One::generate('not a number');
$non_numeric->test(); //works
$numeric->test(); //fatal error
It can be faked up to a point with magic methods:
<?php
class One {
private $test_is_public = false;
function __construct($id){
if(is_numeric($id)){
$this->test_is_public = true;
}
}
private function test(){
echo "test() was called\n";
}
public function __call($name, $arguments){
if( $name=='test' && $this->test_is_public ){
return $this->test();
}else{
throw new LogicException("Method $name() does not exist or is not public\n");
}
}
}
echo "Test should be public:\n";
$numeric = new One('123e20');
$numeric->test();
echo "Test should be private:\n";
$non_numeric = new One('foo');
$non_numeric->test();
I haven't thought about the side effects. Probably, it's only useful as mere proof of concept.

PHP Object Oriented Issue On My Code

Hi please have a look on bellow code.
<?php
class A
{
public $name;
public function getName()
{
return $this->name;
}
}
class B extends A
{
public function setName()
{
$this->name = 'Prasad';
}
}
$obj = new B();
echo $obj->getName();
?>
Here It's display nothing when I echo the name. Related to the $name in class A. Is this issue is with getName or setName? How can I set the $name variable in class A from extended class B. And how can I get that from a class B object. Appreciate any hint or explanation on what I have missed.
You didn't set the name (using $obj->setName()) before.
Technically, it's echoing the $name variable (which is undefined at that point). Unfortunately, it hasn't been set yet. Try using $obj->setName() to set the name.
You are most of the way there with your code, in fact you would have a working example if you added a line telling the code to call the setName() function:
$obj = new B();
$obj->setName();
echo $obj->getName();
More typically you would use a set function with a parameter, then pass the value you want to set. You would also set the $name property to protected, which means the value must be accessed via the set & get methods (more on visibility in the manual):
<?php
class A
{
protected $name;
public function getName()
{
return $this->name;
}
}
class B extends A
{
public function setName($name)
{
$this->name = $name;
}
}
$obj = new B();
$obj->setName('Prasad');
echo $obj->getName();
?>
Yes, as SomeKittens suggested you need to call setName() first.
class A
{
public $name;
public function getName()
{
return $this->name;
}
}
class B extends A
{
public function setName()
{
$this->name = 'Prasad';
}
}
$obj = new B();
$obj->setName();
echo $obj->getName();
However, it might be better to perform the setting of the name in the constructor of B, as:
class A
{
public $name;
public function getName()
{
return $this->name;
}
}
class B extends A
{
public function B()
{
$this->name = 'Prasad';
}
}
$obj = new B();
echo $obj->getName();
This printed Prasad for me using http://writecodeonline.com/php/ to test the code.
Even better, pass the name 'Prasad' when creating the new B object, as:
class A
{
public $name;
public function getName()
{
return $this->name;
}
}
class B extends A
{
public function B( $value = 'Prasad' )
{
$this->name = $value;
}
}
$obj = new B();
echo $obj->getName(), "<br>";
$obj = new B( 'John' );
echo $obj->getName();
It's because you aren't setting the name attribute first. Call B->setName() and then you can get the name by calling B->getName().

PHP Observer Pattern, Issue

Bellow is a PHP script.
I tried to implement the Observer pattern (without MVC structure)... only basic.
The error which is encountered has been specified in a comment.
First I tried to add User objects to the UsersLibrary repository. There was a error such as User::update() does not exists or something.
Why is that error encountered? What fix should be applied and how?
interface IObserver {
public function update(IObservable $sender);
}
interface IObservable {
public function addObserver(IObserver $obj);
public function notify();
}
class UsersLibrary implements IObservable {
private $container;
private $contor;
//private $z;
public function __construct() {//IObserver $a) {
$this->container = array();
$this->contor = 0;
echo "<div>[constructing UsersLibrary...]</div>";
$this->addObserver(new Logger());
//$this->z = $a;
}
public function add($obj) {
echo "<div>[adding a new user...]</div>";
$this->container[$this->contor] = $obj;
$this->contor++;
$this->notify();
}
public function get($index) {
return $this->container[$index];
}
public function addObserver(IObserver $obj) {
$this->container[] = $obj;
}
public function notify() {
echo "<div>[notification in progress...]</div>";
foreach($this->container as $temp) {
//echo $temp;
#################################################################
$temp->update(); //--------ERROR
//Fatal Error: Call to a member function update() on a non-object.
#################################################################
}
//$this->container[0]->update();
//$this->z->update($this);
}
}
class User {
private $id;
private $name;
public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}
public function getId() {
return $this->id;
}
public function getName() {
return $this->name;
}
}
class Logger implements IObserver {
public function __construct() {
echo "<div>[constructing Logger...]</div>";
}
public function update(IObservable $sender) {
echo "<div>A new user has been added.</div>";
}
}
$a = new UsersLibrary(); //new Logger());
//$a->add(new User(1, "DemoUser1"));
//$a->add(new User(2, "DemoUser2"));
$a->add("Demo");
echo $a->get(0);
//echo $a->get(0)->getName();
Your User class is not implementing interface IObserver and therefore is not forced to have the method update().
You have to instantiate a new User() in order to add it to the UsersLibrary:
$library = new UsersLibrary();
$user = new User(1, "Demo");
$library->add($user);
Also, you are mixing Users and Loggers into your UsersLibrary container. Maybe think about separating the containers for them?
You are passing a string instead of an object in your $a->add() call. You should either pass in an object, or alter the code in UserLibrary::add() to wrap it's argument in an appropriate object (or do an object lookup of it sees a string, for instance find a user with that name).
$user = new User(1, "Demo");
$a = new UsersLibrary();
$a->add($user);

redeclaration of instance and static function

class me {
private $name;
public function __construct($name) { $this->name = $name; }
public function work() {
return "You are working as ". $this->name;
}
public static function work() {
return "You are working anonymously";
}
}
$new = new me();
me::work();
Fatal error: Cannot redeclare me::work()
the question is, why php does not allow redeclaration like this. Is there any workaround ?
There is actually a workaround for this using magic method creation, although I most likely would never do something like this in production code:
__call is triggered internally when an inaccessible method is called in object scope.
__callStatic is triggered internally when an inaccessible method is called in static scope.
<?php
class Test
{
public function __call($name, $args)
{
echo 'called '.$name.' in object context\n';
}
public static function __callStatic($name, $args)
{
echo 'called '.$name.' in static context\n';
}
}
$o = new Test;
$o->doThis('object');
Test::doThis('static');
?>
Here is how I think you should do it instead:
class me {
private $name;
public function __construct($name = null) {
$this->name = $name;
}
public function work() {
if ($this->name === null) {
return "You are working anonymously";
}
return "You are working as ". $this->name;
}
}
$me = new me();
$me->work(); // anonymous
$me = new me('foo');
$me->work(); // foo

Categories