I have to different classes in my Slim PHP framework, named OrderController & AddressController. I want to access some function of AddressController inside OrderController to reduce code redundancy.
But can't get a way to do it, I got how to do it in pure PHP setup, but how to do it in Slim PHP framework?
The PHP way to do this is as follows:
class A {
private $xxx;
public function __construct() {
$this->xxx = 'Hello';
}
public function getXXX() {
return $this->xxx;
}
}
class B {
private $a;
public function __construct(A $a) {
$this->a = $a;
}
function getXXXOfA() {
return $this->a->getXXX();
}
}
$a = new A();
$b = new B($a);
$b->getXXXOfA();
How to achieve this dependancy injection in Slim?
Slim PHP Framework
Note: I am using Slim PHP v3
2 solutions come into mind:
-1-
You could also try to have the common functionality in a separate Trait.
-2-
I won't do the
new SecondController($container)
inside the constructor of the FirstController unless you need it at every controller-hit.
I like lazy loading, so it will load only when needed.
If your AddressController and OrderController has same parent class, than move these methods to parent:
class AddressContoller extends Controller {
public function test() {
$this->methodFromParent();
}
}
If not, create new object of that class and call method. Method must be public
class AddressContoller extends Controller {
public function test() {
$order = new OrderController();
$order->publicMethodInOrderClass();
}
}
If your OrderController wants to call a method foo from AccessController, you should think about moving foo somewhere else. That's an good indicator for wrong SRP
There are two possibilities
foo belongs to/is relevant for every Controller and has something to do with controlling: Just move it to the parent class.
foo is relevant to only a few classes: Move it to the class, it belongs to. This could be an helper class, some domain model class, or something else. Maybe you have to intruduce a new class to do this.
After a lot of reseach I finally manage to get a solution! Posting it here so if anyone in future might get help from it:
class FirstController
{
protected $container;
protected $db;
protected $view;
protected $second;
// constructor receives container instance
public function __construct(\Interop\Container\ContainerInterface $container) {
$this->second = new SecondController($container);
$this->container = $container;
$this->db = $this->container->db;
$this->view = $this->container->view;
}
public function LocalFunction(){
$this->second->otherFunction();
//call the functions in other classes as above
}
}
Related
I'm using a Repository pattern in my Laravel project. This pattern is not really explained in the official documentation, except for this snippet:
You may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class.
This is my code, in accordance with the documentation:
class CategoriesController extends Controller
{
protected $repo;
public function __construct(CategoriesRepository $repo)
{
$this->repo = $repo;
}
I've type-hinted the CategoriesRepository so it gets automatically loaded by the Service Container.
However, if I directly create a new instance of the CategoriesController class (without using the Service Container), I have to specify that I need a new instance of the CategoriesRepository too, like this:
$example = new CategoriesController(new CategoriesRepository());
Now, let's suppose I write the following code.
class CategoriesController extends Controller
{
protected $repo;
public function __construct()
{
$this->repo = new CategoriesRepository();
}
This way, I don't have to load the class through the Service Container, nor call it by passing a new instance of CategoriesRepository as the argument, because it's automatically created inside of the constructor.
So, my question is: would this be bad practice? What's the difference between type-hinting as a parameter and creating a new instance inside of the constructor?
Here's the beauty of dependency injection:
Complex initialization
class MyController {
public function __construct(A $a) { }
}
class A {
public function __construct(B $b) { }
}
class B {
public function __construct(C $c) { }
}
class C {
public function __construct(D $d) { }
}
class D {
public function __construct() { }
}
Now you can ask laravel to create that class for you e.g:
$controller = make(MyController::class);
or you can do:
$controller = new MyController(new A(new B(new C(new D())))));
In addition you can specify more complex rules on how to create the variables:
app()->bind(D::class, function ($app) {
$d = new D();
$d->setValueOfSomething($app->make(AnotherClass::class));
return $d;
});
Testing
That's one advantage of dependency injection over manual creation of things. Another is unit testing:
public function testSomeFunctionOfC() {
$this->app->bind(D::class, function () {
$dMock = $this->createMock(D::class);
});
$c = make(C::class);
}
Now when you create C the class D will be the mocked class instead which you can ensure works according to your specification.
I'm learning OOP PHP. I want to call a method from another class to a new class.
For just a example:
<?php
class Aclass {
function aMethod($input)
{
echo 'Hello a world ';
}
}
?>
And i want to call the method aMethod from the class 'Aclass' into the new class.
<?php
class Bclass {
//calling the method here?
}
?>
i tried extending , still not working for me.
Thanks.
In your class Bclass you should create some functions. In case below you are creating a new instance of Aclass and then using function aMethod.
Example
<?php
class Bclass {
public function __construct() {
$a = new Aclass();
$a->aMethod("some_text");
}
}
?>
Other way is extend Bclass. In this case your class Bclass extends everything what's in Aclass so you can use it just with $this.
Example
<?php
class Bclass extends Aclass {
public function __construct() {
$this->aMethod("some_text");
}
}
?>
Also your function aMethod in Aclass should have public or protected visibility. Public if you create an instance, protected if you extends. More informations can be found in manuals at the end.
Example
<?php
class Aclass {
public function aMethod($input) // protected if you will extend this class
{
echo 'Hello a world ';
}
}
?>
You can of course use both methods not only in __construct but also in other functions.
Manuals
PHP: Visibility
PHP: Constructors and Destructors
For this I'd use dependency injection. Which is just a fancy way of saying "sending an object of the A class when creating B".
In other words, something like this:
class typeA {
public function __construct () {};
public function test () {
return 'Test string';
}
}
class typeB {
protected $testObj;
public function __construct (typeA $testCase) {
$this->testObj = $testCase;
}
public function getTest () {
return $this->testObj->test ();
}
}
$a = new typeA ();
$b = new typeB ($a);
echo $b->getTest ();
Constructors are meant to be used to create an object that's ready to be used, which is why I've just stored the dependency inside the typeB object itself. Then, in the getTest() method I invoke the test() method of the object I'm depending upon, in order to get the needed data from it.
Doing it in this manner will allow you to write flexible OOP code, which can easily be expanded and extended as you require. Hiding the dependencies inside the constructors, by creating objects there, creates a hidden and hard dependency. Something which makes it a lot harder, if not down right impossible, to properly leverage the extensible nature of the class-based designs.
class TopParent
{
protected function foo()
{
$this->bar();
}
private function bar()
{
echo 'Bar';
}
}
class MidParent extends TopParent
{
protected function foo()
{
$this->midMethod();
parent::foo();
}
public function midMethod()
{
echo 'Mid';
}
public function generalMethod()
{
echo 'General';
}
}
Now the question is if I have a class, that extends MidParent because I need to call
class Target extends MidParent
{
//How to override this method to return TopParent::foo(); ?
protected function foo()
{
}
}
So I need to do this:
$mid = new MidParent();
$mid->foo(); // MidBar
$taget = new Target();
$target->generalMethod(); // General
$target->foo(); // Bar
UPDATE
Top parent is ActiveRecord class, mid is my model object. I want to use model in yii ConsoleApplication. I use 'user' module in this model, and console app doesn't support this module. So I need to override method afterFind, where user module is called. So the Target class is the class that overrides some methods from model which uses some modules that console application doesn't support.
Try this (http://php.net/manual/en/language.oop5.final.php - not allow to overriding in the childrens):
final protected function foo()
{
$this->midMethod();
parent::foo();
}
in class MidParent and the class Target can't overrides this method.
Directly - you can't. This is how OOP works.
You can do it by a little redesign, e.g. in MidParent add method:
protected function parentFoo()
{
parent::foo();
}
and in Target:
public function foo()
{
$this->parentFoo();
}
But, again, this is only a workaround to solve your question and not a solution.
Actually, you can do this like this way with Reflection::getParentClass():
class Foo
{
public function test($x, $y)
{
echo(sprintf('I am test of Foo with %s, %s'.PHP_EOL, $x, $y));
}
}
class Bar extends Foo
{
public function test()
{
echo('I am test of Bar'.PHP_EOL);
parent::test();
}
}
class Baz extends Bar
{
public function test()
{
$class = new ReflectionClass(get_class($this));
return call_user_func_array(
[$class->getParentClass()->getParentClass()->getName(), 'test'],
func_get_args()
);
}
}
$obj = new Baz();
$obj->test('bee', 'feo'); //I am test of Foo with bee, feo
-but this is an architecture smell in any case. If you need something like this, that should tell you: you're doing something wrong. I don't want to recommend anyone to use this way, but since it's possible - here it is.
#AnatoliyGusarov, your question is interesting and in a sense you can achieve what you desire using yii and php advances features like Traits and Traits in Yii.
Given that it depends on what version of php you are using.However in yii you can achieve this by behaviors and check this SOQ.
In a nutshell you have to use language advanced features or YII framework features to come around this kind of issues,but that boils down to actual requirements
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 am looking for the best way to go about testing the following static method (specifically using a Doctrine Model):
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
Ideally, I would use a mock object to ensure that fromArray (with the supplied user data) and save were called, but that's not possible as the method is static.
Any suggestions?
Sebastian Bergmann, the author of PHPUnit, recently had a blog post about Stubbing and Mocking Static Methods. With PHPUnit 3.5 and PHP 5.3 as well as consistent use of late static binding, you can do
$class::staticExpects($this->any())
->method('helper')
->will($this->returnValue('bar'));
Update: staticExpects is deprecated as of PHPUnit 3.8 and will be removed completely with later versions.
There is now the AspectMock library to help with this:
https://github.com/Codeception/AspectMock
$this->assertEquals('users', UserModel::tableName());
$userModel = test::double('UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
$userModel->verifyInvoked('tableName');
I would make a new class in the unit test namespace that extends the Model_User and test that. Here's an example:
Original class:
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
Mock Class to call in unit test(s):
use \Model_User
class Mock_Model_User extends Model_User
{
/** \PHPUnit\Framework\TestCase */
public static $test;
// This class inherits all the original classes functions.
// However, you can override the methods and use the $test property
// to perform some assertions.
}
In your unit test:
use Module_User;
use PHPUnit\Framework\TestCase;
class Model_UserTest extends TestCase
{
function testCanInitialize()
{
$userDataFixture = []; // Made an assumption user data would be an array.
$sut = new Mock_Model_User::create($userDataFixture); // calls the parent ::create method, so the real thing.
$sut::test = $this; // This is just here to show possibilities.
$this->assertInstanceOf(Model_User::class, $sut);
}
}
Found the working solution, would to share it despite the topic is old.
class_alias can substitute classes which are not autoloaded yet (works only if you use autoloading, not include/require files directly).
For example, our code:
class MyClass
{
public function someAction() {
StaticHelper::staticAction();
}
}
Our test:
class MyClassTest
{
public function __construct() {
// works only if StaticHelper is not autoloaded yet!
class_alias(StaticHelperMock::class, StaticHelper::class);
}
public function test_some_action() {
$sut = new MyClass();
$myClass->someAction();
}
}
Our mock:
class StaticHelperMock
{
public static function staticAction() {
// here implement the mock logic, e.g return some pre-defined value, etc
}
}
This simple solution doesn't need any special libs or extensions.
Mockery's Alias functionality can be used to mock public static methods
http://docs.mockery.io/en/latest/reference/creating_test_doubles.html#creating-test-doubles-aliasing
Another possible approach is with the Moka library:
$modelClass = Moka::mockClass('Model_User', [
'fromArray' => null,
'save' => null
]);
$modelClass::create('DATA');
$this->assertEquals(['DATA'], $modelClass::$moka->report('fromArray')[0]);
$this->assertEquals(1, sizeof($modelClass::$moka->report('save')));
One more approach:
class Experiment
{
public static function getVariant($userId, $experimentName)
{
$experiment = self::loadExperimentJson($experimentName):
return $userId % 10 > 5; // some sort of bucketing
}
protected static function loadExperimentJson($experimentName)
{
// ... do something
}
}
In my ExperimentTest.php
class ExperimentTest extends \Experiment
{
public static function loadExperimentJson($experimentName)
{
return "{
"name": "TestExperiment",
"variants": ["a", "b"],
... etc
}"
}
}
And then I would use it like so:
public function test_Experiment_getVariantForExperiment()
{
$variant = ExperimentTest::getVariant(123, 'blah');
$this->assertEquals($variant, 'a');
$variant = ExperimentTest::getVariant(124, 'blah');
$this->assertEquals($variant, 'b');
}
Testing static methods is generally considered as a bit hard (as you probably already noticed), especially before PHP 5.3.
Could you not modify your code to not use static a method ? I don't really see why you're using a static method here, in fact ; this could probably be re-written to some non-static code, could it not ?
For instance, could something like this not do the trick :
class Model_User extends Doctrine_Record
{
public function saveFromArray($userData)
{
$this->fromArray($userData);
$this->save();
}
}
Not sure what you'll be testing ; but, at least, no static method anymore...