I have got a trait
trait Foo{
protected static function foo(){
echo 'Hello';
}
}
and a class
class Bar{
use Foo;
private static function foo(){
Foo::foo();
echo ' World!';
}
}
I cannot use Foo:foo(). What can I do to achieve the desired effect?
EDIT
Using
use Foo {foo as parentFoo}
private static function foo(){
self::parentFoo();
echo ' World!';
}
did the trick.
You can do something like this:
class Bar{
use Foo {
Foo::foo as foofoo;
}
private static function foo(){
self::foofoo();
echo ' World!';
}
}
Are you allowed to rename your trait method foo to fooo?
If yes, please do and replace Foo::foo() with Foo:fooo() in your class method body before following static call syntax (by adding static keyword to your trait function definition)
<?php
trait Foo
{
protected static function Fooo()
{
echo 'Hello';
}
}
class Bar
{
use Foo;
private static function foo()
{
self::fooo();
echo ' World!';
}
public static function expose()
{
echo self::foo();
}
}
echo Bar::expose();
EDIT:
Obviously, the answer to my question was "No, you're not allowed to rename the trait method", for which case, you've pointed out a solution related to native conflict resolution embedded in PHP:
http://php.net/manual/en/language.oop5.traits.php#language.oop5.traits.conflict
Related
nothing is displayed at runtime. xdebug does not run. this simple example doesn't work.
ini_set("display_errors", 1);
error_reporting(E_ALL);
abstract class Hello
{
protected function hello();
}
class Helloworld extends Hello
{
public $world;
public function __construct($world){
$this->world = $world;
}
public function hello() {
echo 'Hello + '.$this->world;
}
}
class Hiotherworld extends Hello
{
public $world;
public function __construct($world){
$this->world = $world;
}
public function hello(){
echo 'Hi + '.$this->world;
}
}
$hello = new Helloworld("Earth");
$hello->hello();
$hi = new Hiotherworld("Mars");
$hi->hello();
Fatal error: Non-abstract method Hello::hello() must contain body:
protected function hello();
You can't change the visibility of a method in a subclass. You declared hello() as protected so it must be protected in sub classes as well.
I guess you wanted to declare it as public in Hello as protected makes no sense in this context. Also you missed the abstract keyword (Thanks #rNix) And you should move the declaration of $world to the base class:
Finally Hello should look like this:
abstract class Hello
{
$protected $world;
abstract public function hello();
}
Change it
abstract class Hello
{
protected function hello(){}
}
working for me.
I didn't get why the first output of the code prints "Bar::testPrivate" as we are calling the test method of the parent class using sub class's instance.So, when calling the first line of code inside the test function which is "$this->testPrivate();" should call testPrivate method of the sub class hence printing "Foo::testPrivate" and not "Bar::testPrivate".
<pre>
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
</pre>
Your class Foo doesn't have a test() method. You can call $myFoo->test() because the method test() is inherited from class Bar. You'll have to override the method test() within class Foo just as you did with methods testPrivate() and testPublic().
You are correct that it is calling the method of the base class, but in this case Bar is your base class. Check out the example here.
If you are looking to inherit all the functions from your base (parent) class then you should explicitly call it's constructor in the child class. Otherwise you will need to override those methods. Also, when using the actual instance (i.e. you created an object) functions declared private are only available to that class. Use protected for classes that will inherit that function. e.g.:
class Foo {
public function __construct() {
echo "Foo constructed...\n";
$this->fooOnly();
}
private function fooOnly() {
echo "Called 'fooOnly()'\n"; //Only available to class Foo
}
protected function useThisFoo() {
echo "Called 'useThisFoo()'\n"; //Available to Foo and anything that extends it.
}
}
class Bar extends Foo {
public function __construct() {
parent::__construct(); //Now Bar has everything from Foo
}
public function testFooBar() {
//$this->fooOnly(); //Fail - private function
$this->useThisFoo(); //Will work - protected function is available to Foo and Bar
}
}
$bar = new Bar();
$bar->testFooBar(); //Works - public function will internally call protected function.
//$bar->fooOnly(); //Fail - private function can't be accessed in global space
//$bar->useThisFoo(); //Fail again - protected function can't be access in global space
If i extend a static class in PHP, and the parent class refers to "self::", will this refer to the self in the extended class?
So, for example
<?php
Class A
{
static $var
public static function guess(){self::$var = rand(); return $var}
}
Class B extends Class A
{
public static function getVar(){return self::$var}
}
If I ran
B::guess();
then B::getVar();
is the value for Var stored in A::$var or B::$var?
Thank you.
Late static binding was introduced in PHP 5.3, it allows you to control this behavior.
It's easy to test:
class ClassA {
public static function test(){ self::getVar(); }
public static function getVar(){ echo 'A'; }
}
class ClassB extends ClassA {
public static function getVar(){ echo 'B'; }
}
ClassA::test(); // prints 'A'
ClassB::test(); // also prints 'A'
... hope that helps :)
Additional information, usage of self or $this is different into extended classes
class ClassA {
public function test(){ self::getVar(); }
public function test2(){ $this->getVar(); }
public function getVar(){ echo 'A'; }
}
class ClassB extends ClassA {
public function getVar(){ echo 'B'; }
}
$classB = new ClassB();
$classB->test(); // prints 'A'
$classB->test2(); // prints 'B'
Here's my code:
class Manual extends controller {
function Manual(){
parent::Controller();
$myVar = 'blablabla';
}
function doStuff(){
echo $myVar; // Doesn't work.
}
}
I've tried various methods to make it work, but I've can't get my head around it. What can I do?
Thanks
In your code, $myVar is local to each method.
Perhaps you meant $this->myVar?
You need to use the $this 'pointer'.
e.g.:
class Test
{
protected $var;
public function __construct()
{
$this->var = 'foobar';
}
public function getVar()
{
return $this->var;
}
};
class Manual extends controller {
private $myVar;
function Manual(){
parent::Controller();
$this->$myVar = 'blablabla';
}
function doStuff(){
echo $this->$myVar;
}
}
Even more OOP-like with Setters/Getters
class Manual extends controller {
private $myVar;
function Manual(){
parent::Controller();
setMyVar('blablabla');
}
function doStuff(){
echo getMyVar();
}
function getMyVar() {
return $this->myVar;
}
function setMyVar($var) {
$this->myVar = $var;
}
function doStuff(){
echo $this->myVar;
}
The variable $myVar should be property of a class, and you can not do:
echo $myVar;
You should do:
$this->myVar;
As written, $myVar is local to both methods.
You need to declare $myVar as a property in the class body
protected $myVar;
and then use the pseudo variable $this to access the property in methods, including the constructor
$this->myVar;
$myVar field must be declarated as public/protected in the parent class or declarated in the descedent class, and in yours doStuff() method you must write $this->myVar not the $myVar
I want to check is a function exists in a library that I am creating, which is static. I've seen function and method_exists, but haven't found a way that allows me to call them in a relative context. Here is a better example:
class myClass{
function test1()
{
if(method_exists("myClass", "test1"))
{
echo "Hi";
}
}
function test2()
{
if(method_exists($this, "test2"))
{
echo "Hi";
}
}
function test3()
{
if(method_exists(self, "test3"))
{
echo "Hi";
}
}
}
// Echos Hi
myClass::test1();
// Trys to use 'self' as a string instead of a constant
myClass::test3();
// Echos Hi
$obj = new myClass;
$obj->test2();
I need to be able to make test 3 echo Hi if the function exists, without needing to take it out of static context. Given the keyword for accessing the class should be 'self', as $this is for assigned classes.
static::class is available since PHP 5.5, and will return the "Late Static Binding" class name:
class myClass {
public static function test()
{
echo static::class.'::test()';
}
}
class subClass extends myClass {}
subClass::test() // should print "subClass::test()"
get_called_class() does the same, and was introduced in PHP 5.3
class myClass {
public static function test()
{
echo get_called_class().'::test()';
}
}
class subClass extends myClass {}
subClass::test() // should print "subClass::test()"
The get_class() function, which as of php 5.0.0 does not require any parameters if called within a class will return the name of the class in which the function was declared (e.g., the parent class):
class myClass {
public static function test()
{
echo get_class().'::test()';
}
}
class subClass extends myClass {}
subClass::test() // prints "myClass::test()"
The __CLASS__ magic constant does the same [link].
class myClass {
public static function test()
{
echo __CLASS__.'::test()';
}
}
class subClass extends myClass {}
subClass::test() // prints "myClass::test()"
Update:
Ahh, apologies. I was temporarily blind :) You'll want to use the magic constant __CLASS__
e.g.
if (method_exists(__CLASS__, "test3")) { echo "Hi"; }
for all situations… the best usage would be…
if method_exist(…) && is_callable(…)
For testing example:
class Foo {
public function PublicMethod() {}
private function PrivateMethod() {}
public static function PublicStaticMethod() {}
private static function PrivateStaticMethod() {}
}
$foo = new Foo();
$callbacks = array(
array($foo, 'PublicMethod'),
array($foo, 'PrivateMethod'),
array($foo, 'PublicStaticMethod'),
array($foo, 'PrivateStaticMethod'),
array('Foo', 'PublicMethod'),
array('Foo', 'PrivateMethod'),
array('Foo', 'PublicStaticMethod'),
array('Foo', 'PrivateStaticMethod'),
);
foreach ($callbacks as $callback) {
var_dump($callback);
var_dump(method_exists($callback[0], $callback[1])); // 0: object / class name, 1: method name
var_dump(is_callable($callback));
echo str_repeat('-', 40), "n";
}
Source here