I am trying to extend a PHP class without rewriting the whole thing. Here is an example:
<?
$a = new foo();
print $a->xxx();
$b = new bar();
print $b->xxx();
class foo {
const something = 10;
public function xxx() {
$this->setSomething();
return $this->something;
}
private function setSomething() {
$this->something = self::something;
}
}
class bar extends foo {
public function xxx() {
$this->setSomething();
$this->something++;
return $this->something;
}
}
?>
However when I run the script I get the following error:
Fatal error: Call to private method foo::setSomething() from context 'bar' in test.php on line 23
It would seem that bar is not inheriting the private function setSomething(). How would I fix this without modifying the foo class?
No, you can not fix this without modifying the foo class. Because an inherited class can not access parent class's private members. It's a very basic oop rule.
Declare setSomething() as protected. It'll be solved.
See manual
Private members are not inheritable, you can not use them in sub class. They are not accessible outside the class.
You must need to make that function as protected or public. Protected members are accessible to that class and for the inherited class. So, your best bet is to make that function Protected.
bar is inheriting the function alright, but it can't call it. That's the whole point of private methods, only the declaring class can call them.
Try reflection
http://php.net/manual/en/class.reflectionclass.php
Also:
Call private methods and private properties from outside a class in PHP
Did you try this?
class bar extends foo {
public function xxx() {
$this->something = parent::xxx();
$this->something++;
return $this->something;
}
}
Note the parent::xxx(); is public, so it should work... even though it looks like a static call.
Without modifying the original class, there is no way for the inherited class to directly call private methods of the parent class.
Related
My Question is. I have a class i want to test (myClass). In myClass there is a function wich calls a private function thats also in the myClass.
I know i can't test private functions. Is it possible to tell phpunit to call another function instead of the private?
Example
$this->testclass is now the class i want to test
$this->testclass = new \stdClass();
$this->testclass->mock = $this->getMockBuilder('myClass')->getMock();
Outside my testcase i have created a fake class.
$this->mockextended = new \stdClass();
$this->mockextended->mock = new MOCKEXTENDEDCLASSES();
in the $this->mockextended i have a public function.
the function i want to test
public function TestMe(){
$this->somePrivateFunctioniHate(); <==== this is the pain in my ass
}
and the private function
private function somePrivateFunctioniHate(){
//come code
}
What i want to do is. the function TestMe is calling a private function.
Is it possible to tell phpunit to override the private function and call another function thats inside $this->mockextended;
I have tried it like this.
$this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction()
only this gives me a nice error. I did this before and it worked. Called it like this
EDIT
For people who don't understand my question.
I have another function that calls another class. I din't want to have another class in my test so i created a fake Class outside my testcase. Inserted the same functions as the class the function wants to include. Did it like this
$this->testclass->chunks = new \stdClass();
//MOCKchunckTpl is the fake class outside my testcase
$this->testclass->chunks->config = new MOCKchunkTpl();
This works. Whenever a function wants to call $this->testclass->chunks->config->Somefunction(); it will be redirected to my fake class.
BUT when i try to do the same with a function thats calling a private function. Like $this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction() it gives a nice error
Fatal error: Can't use method return value in write context in
Short answer: No, there isn't. There is no way for PHPUnit to manipulate private methods.
Mocks are for faking the behavior of classes, which depend on the class you want to test. If you need to overwrite a private method, there is something wrong in your architecture. Private methods should be tested by simple testing the public methods in which they are used. If you need to test it separately, declare it public.
EDIT: Here is an example how you'd test a simple code using a private method or putting this private method in another class:
1. Private method
class MyClass {
public function myMethod() {
return $this->myPrivateMethod();
}
private function myPrivateMethod() {
return 2;
}
}
And the test class:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$myClass = new MyClass();
// don't mind the private method, just test if the public method is working
$this->assertEquals(2, $myClass->myMethod());
}
}
1. Second class
class MyClass {
public $dependentClass;
public function myMethod() {
return $this->dependentClass->dependentMethod();
}
}
And the dependent class:
class DependentClass {
public function dependentMethod() {
return 38943;
}
}
Testing MyClass with the DependentClass:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$dependentMock = $this->getMockBuilder("DependentClass")->getMock();
$dependentMock->expects($this->any())
->method("dependentMethod")
->willReturn($this->returnValue(2));
$myClass = new MyClass();
$myClass->dependentClass = $dependentMock;
$this->assertEquals(2, $myClass->myMethod());
}
Although we defined a whole other return in DependentClass, the test will still pass, because we mocked it and are able to define every behavior we'd expect DependentClass to have.
But to cleanly test the project, we need to define another test for DependentClass as well to test, if this class is working. This test should fail if it is not working anymore, not the test for MyClass.
I'm having a hard time trying to understand the output of the following code:
class Bar
{
public function test() {
$this->testPublic();
$this->testPrivate();
}
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();
Output:
Foo::testPublic
Bar::testPrivate
Class Foo overrides testPublic() and testPrivate(), and inherits test(). When I call test(), there is an explicit instruction envolving $this pseudo variable, so after I created $myFoo instance, the final calls of test() function would be $myFoo->testPublic() and $myFoo->testPrivate(). The first output is as I expected, since I overrode testPublic() method to echo Foo::testPublic. But the second output makes no sense to me. Why is it Bar::testPrivate if I overrode testPrivate() method? Also the private method from parent class wouldn't be inherited anyway, by definition! It makes no sense. Why is the parent method the one being called???
The problem with your code is that the method Bar::testPrivate is private, therefore it cannot be overridden by child classes. For starters, I recommend that you read up on visibility in PHP - http://www.php.net/manual/en/language.oop5.visibility.php. There you will learn that only public and protected class member methods/properties can be overridden, private ones cannot.
As a good example, try changing the visibility of the Bar::testPrivate method to either public or protected, without altering anything else in your example code. Now try and run your tests. What happens? This:
PHP Fatal error: Access level to Foo::testPrivate() must be protected (as in class Bar) or weaker
The big question is: "why?". Well, you have now overridden Bar::testPrivate with a private Foo:testPrivate. This new private method is out of scope for Bar::test, because private class members are visible to their current class only, NOT the parent/child classes!
Therefore, as you can see, OOP provides a certain amount of encapsulation for class members, and it can be quite confusing if you don't take the time to understand it.
I'm wondering why the following code won't print out anything. I'm trying to access Bar::$some_var from method in parent class. Where Bar::$some_var is defined in it's constructor.
I've tried using self::$some_var and static::$some_var in Foo::hello() but neither worked. Do I have to make $some_var static?
class Foo {
private $some_var;
public function __construct() {
$this->some_var = 5;
}
public function hello() {
print $this->some_var;
}
}
class Bar extends Foo {
public function __construct() {
$this->some_var = 10;
}
}
$bar = new Bar();
$bar->hello();
Thanks in advance.
private makes a member variable unavailable outside of a class. You need to use protected to allow extending classes to have access to that variable.
protected $some_var;
See Visibility
Your class variable cannot be private if you would like your child class to access it.
Try protected instead and it should work!
:: operator is used to access class items (constants, static
variables, static methods)
-> operator is used to access object items (non static properties and methods)
anyway in your code the problem is visibility of $some_var. It has to be almost protected, public will also work
I have a protected function that is defined within a certain class. I want to be able to call this protected function outside of the class within another function. Is this possible and if so how may I achieve it
class cExample{
protected function funExample(){
//functional code goes here
return $someVar
}//end of function
}//end of class
function outsideFunction(){
//Calls funExample();
}
Technically, it is possible to invoke private and protected methods using the reflection API. However, 99% of the time doing so is a really bad idea. If you can modify the class, then the correct solution is probably to just make the method public. After all, if you need to access it outside the class, that defeats the point of marking it protected.
Here's a quick reflection example, in case this is one of the very few situations where it's really necessary:
<?php
class foo {
protected function bar($param){
echo $param;
}
}
$r = new ReflectionMethod('foo', 'bar');
$r->setAccessible(true);
$r->invoke(new foo(), "Hello World");
That's the point of OOP - encapsulation:
Private
Only can be used inside the class. Not inherited by child classes.
Protected
Only can be used inside the class and child classes. Inherited by child classes.
Public
Can be used anywhere. Inherited by child classes.
If you still want to trigger that function outside, you can declare a public method that triggers your protected method:
protected function b(){
}
public function a(){
$this->b() ;
//etc
}
If the parent's method is protected, you can use an anonymous class:
class Foo {
protected function do_foo() {
return 'Foo!';
}
}
$bar = new class extends Foo {
public function do_foo() {
return parent::do_foo();
}
}
$bar->do_foo(); // "Foo!"
https://www.php.net/manual/en/language.oop5.anonymous.php
You can override this class with another where you make this public.
class cExample2 extends cExample {
public function funExample(){
return parent::funExample()
}
}
(note this won't work with private members)
But the idea of private and protected members is to NOT BE called from outside.
Another option (PHP 7.4)
<?php
class cExample {
protected function funExample(){
return 'it works!';
}
}
$example = new cExample();
$result = Closure::bind(
fn ($class) => $class->funExample(), null, get_class($example)
)($example);
echo $result; // it works!
If you want to share code between your classes you can use traits, but it depends how you want use your function/method.
Anyway
trait cTrait{
public function myFunction() {
$this->funExample();
}
}
class cExample{
use cTrait;
protected function funExample() {
//functional code goes here
return $someVar
}//end of function
}//end of class
$object = new cExample();
$object->myFunction();
This will work, but keep in mind that you don't know what your class is made of this way. If you change the trait then all of your classes which use it will be altered as well. It's also good practice to write an interface for every trait you use.
here i can give you one example like below
<?php
class dog {
public $Name;
private function getName() {
return $this->Name;
}
}
class poodle extends dog {
public function bark() {
print "'Woof', says " . $this->getName();
}
}
$poppy = new poodle;
$poppy->Name = "Poppy";
$poppy->bark();
?>
or one another way to use with latest php
In PHP you can do this using Reflections. To invoke protected or private methods use the setAccessible() method http://php.net/reflectionmethod.setaccessible (just set it to TRUE)
I am using Laravel. i was facing issue while access protected method outside of class.
$bookingPriceDetails = new class extends BookingController {
public function quotesPrice( $req , $selectedFranchise) {
return parent::quotesPrice($req , $selectedFranchise);
}
};
return $bookingPriceDetails->quotesPrice($request , selectedFranchisees());
here BookingController is Class name from which i want to get protected method. quotesPrice( $req , $selectedFranchise) is method that i want to access in different Class.
I have the following class in PHP
class MyClass
{
// How to declare MyMember here? It needs to be private
public static function MyFunction()
{
// How to access MyMember here?
}
}
I am totally confused about which syntax to use
$MyMember = 0; and echo $MyMember
or
private $MyMember = 0; and echo $MyMember
or
$this->MyMember = 0; and echo $this->MyMember
Can someone tell me how to do it?
I am kind of not strong in OOPS.
Can you do it in the first place?
If not, how should I declare the member so that I can access it inside static functions?
class MyClass
{
private static $MyMember = 99;
public static function MyFunction()
{
echo self::$MyMember;
}
}
MyClass::MyFunction();
see Visibility and Scope Resolution Operator (::) in the oop5 chapter of the php manual.
This is a super late response but it may help someone..
class MyClass
{
private $MyMember;
public static function MyFunction($class)
{
$class->MyMember = 0;
}
}
That works. You can access the private member that way, but if you had $class you should just make MyFunction a method of the class, as you would just call $class->MyFunction(). However you could have a static array that each instance is added to in the class constructor which this static function could access and iterate through, updating all the instances. ie..
class MyClass
{
private $MyMember;
private static $MyClasses;
public function __construct()
{
MyClass::$MyClasses[] = $this;
}
public static function MyFunction()
{
foreach(MyClass::$MyClasses as $class)
{
$class->MyMember = 0;
}
}
}
Within static methods, you can't call variable using $this because static methods are called outside an "instance context".
It is clearly stated in the PHP doc.
<?php
class MyClass
{
// A)
// private $MyMember = 0;
// B)
private static $MyMember = 0;
public static function MyFunction()
{
// using A) // Fatal error: Access to undeclared static property:
// MyClass::$MyMember
// echo MyClass::$MyMember;
// using A) // Fatal error: Using $this when not in object context
// echo $this->MyMember;
// using A) or B)
// echo $MyMember; // local scope
// correct, B)
echo MyClass::$MyMember;
}
}
$m = new MyClass;
echo $m->MyFunction();
// or better ...
MyClass::MyFunction();
?>
Static or non-static?
Did you ever asked yourself this question?
You can not access non static parameters / methods from inside
static method (at least not without using dependency injection)
You can however access static properties and methods from with in non-static method (with self::)
Properties
Does particular property value is assign to class blueprint or rather to it instance (created object from a class)?
If the value is not tight to class instance (class object) then you could declare it as as static property.
private static $objectCreatedCount; // this property is assign to class blueprint
private $objectId; // this property is assign explicitly to class instance
Methods
When deciding on making a method static or non-static you need to ask yourself a simple question. Does this method need to use $this? If it does, then it should not be declared as static.
And just because you don't need the $this keyword does not
automatically mean that you should make something static (though the
opposite is true: if you need $this, make it non-static).
Are you calling this method on one individual object or on the class in general? If you not sure which one to use because both are appropriate for particular use case, then always use non-static. It will give you more flexibility in future.
Good practice is to always start to design your class as non-static and force static if particular us case become very clear.
You could try to declare your parameters as static... just so you can access it from static method but that usually is not what you want to do.
So if you really need to access $this from static method then it means that you need to rethink/redesign your class architecture because you have don it wrong.