So, I've got a question that, while based in Laravel, might just end up being something basic in PHP that I either missed or forgot. Or it may just turn out there is no "textbook/clean/standard" way of doing it.
A Question of Clutter
Anyway, I'm creating a fair number of Form Requests in Laravel (it's a sizable "app") and I'm constantly struck by how unnecessarily redundant their inclusion can be:
<?php
namespace App\Http\Controllers\Account;
use App\Http\Requests\SubscriberRequest;
use App\Http\Requests\SubscriberUpdateRequest;
use App\Http\Requests\SubscriberExtRequest;
use App\Http\Requests\SubscriberExtUpdateRequest;
class MailingListController extends BaseController
{
public function store(SubscriberRequest)
{
// code here
}
public function update(SubscriberUpdateRequest)
{
// code here
}
public function ExtCreate(SubscriberExtRequest)
{
// code here
}
public function ExtUpdate(SubscriberExtUpdateRequest)
{
// code here
}
}
The Alternative
Putting it up above moves the clutter out of the controller itself, but ends up being more work to create and maintain. I'm finding it's easier to just do it like this:
<?php
namespace App\Http\Controllers\Account;
class MailingListController extends BaseController
{
public function store(\App\Http\Requests\SubscriberRequest)
{
// code here
}
public function update(\App\Http\Requests\SubscriberUpdateRequest)
{
// code here
}
public function ExtCreate(\App\Http\Requests\SubscriberExtRequest)
{
// code here
}
public function ExtUpdate(\App\Http\Requests\SubscriberExtUpdateRequest)
{
// code here
}
}
The Question
Obviously, either of these ways is "fine" and "valid." This is hardly a high-priority issue. But the form requests are all coming from the same namespace. And when I'm working with a couple dozen controllers, the typing/copying can get tedious.
So, with all that in mind, is there an "ideal" PHP class-based solution to this problem? And, failing that, should I resort to an app-wide constant/variable? (Or is there some other trick anyone would recommend?)
If you are using php 7+
Here is a nice way to keep your namespace inclusion cleaner.
use some\namespace\{ClassA, ClassB, ClassC as C};
Related
I'm working on a tool exporting tests as PHP/PHPUnit and I'm facing a small problem. To explain briefly, the test scripts only contain calls to an actionwords object, which contains all the logic of the test (in order to factors various steps from different test scenario).
An example might be clearer:
require_once('Actionwords.php');
class CoffeeMachineHiptestPublisherSampleTest extends PHPUnit_Framework_TestCase {
public $actionwords = new Actionwords();
public function simpleUse() {
$this->actionwords->iStartTheCoffeeMachine();
$this->actionwords->iTakeACoffee();
$this->actionwords->coffeeShouldBeServed();
}
}
Here in the coffeeShouldBeServed method, I need to run an assertion, but that's not possible as the Actionwords class does not extend PHPUnit_Framework_TestCase (and I'm not sure it should, it's not a test case, just a set of helpers).
Currently the solution I found is to pass the tests object to the action words and use the reference for the assertions, something like that.
class CoffeeMachineHiptestPublisherSampleTest extends PHPUnit_Framework_TestCase {
public $actionwords;
public function setUp() {
$this->actionwords = new Actionwords($this);
}
}
class Actionwords {
var $tests;
function __construct($tests) {
$this->tests = $tests;
}
public function coffeeShouldBeServed() {
$this->tests->assertTrue($this->sut->coffeeServed);
}
}
It works fine but I don't find it really elegant. I'm not a PHP developer so there might be some better solutions that feel more "php-ish".
Thanks in advance,
Vincent
The assertion methods are static so you can use PHPUnit_Framework_Assert::assertEquals(), for instance.
This is the basic class design
class CustomModule {
public __construct() { }
//Run me first automaticly
public function exec($str) { }
}
class Randomizer extends CustomModule {
public __construct() { }
//Call me
public function exec($str) { }
}
As I am designing a plugin/module system for extern developers I need the CustomModule->exec() to run first, I do not want to leave it up to the devs to have to call base->exec($str).
I want CustomModule::exec() called automaticly before Randomizer::exec() is called without having to put code in Randomizer::exec(). Is This Possible perhaps with magic function?
In my opinion, i would use this way:
Instead of calling _construct in exec of Randomizer, you can define a constructor in Randomizer and call parent::_construct
class CustomModule {
//Run me first automaticly
public function exec($str) { }
public __construct($str) {
$this->exec($str);
}
}
class Randomizer extends CustomModule {
//Call me
public function exec($str) {
parent::__construct($str);
}
}
If your object requires some initialization before you can "release* it into the rest of application, then it means that you need a factory for this. This is how you should be solving it, if you require to call some method only once.
If such execution happens each time you call exec() method, then instead you should be using some sort of containment (in a form of decorator or just you standard composition of objects).
Basically, you need to restructure your code.
After a bit more thought I realized this is BAD design. I have to keep the code base simple and scaleable and this would only make a mess in large projects.
As the only program calling the Randomizer::exec() is my inhouse built program I can just call CustomModule::exec() on the previous line and get a boolean response to see if it should continue to the next line.
Sorry to have to end this Q' short
I have a question about extending a class in PHP.
The examples I see on the php site just have 1 line of code in the method...is it the same if the method has tons of code??
If this is the base class:
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
Then do I have to copy all the code over if I want to use the same method, but change only 1 or 2 things?
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
// do I have to copy all of the other code and then add my code??
}
}
This seems a little not DRY to me...
Yes, unless those 1 or 2 things happen to be at the beginning or the end. You can call the parent function via
parent::WithWayTooMuchCode();
Which you can place anywhere in the child/overridden method.
If it doesn't feel DRY, consider splitting the function into smaller methods.
do I have to copy all the code over if I want to use the same method,
but change only 1 or 2 things?
No, you don't have to copy all of the code, assuming you're adding to the function and not removing pieces of it.
so it follows:
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
parent::WithWayTooMuchCode();
//additionally, do something else
}
}
$moc = new MyOwnClass();
$moc->WithWayTooMuchCode();
You can use the parent::WithWayTooMuchCode() wich will execute the parent method and after you can add your code. It will look like this :
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode {
parent::WithWayTooMuchCode()
// do I have to copy all of the other code and then add my code??
}
}
You can write down a separate function for that things that you want to do separately in parent class and then Call then in you way.
In other words, separate out the things you need to do separately ans create a function for them. And call them separately in child class. The final function in child class will call parent class function as well those separate functions.
You have a few choices. Assuming;
class BaseClass {
public function WithWayTooMuchCode {
// like 100 lines of code here
}
}
You can do
class MyOwnClass extends BaseClass {
public function AnotherFunction() {
// put other code here
}
}
This allows you to do MyOwnClass->AnotherFunction() and MyOwnClass->WithWayTooMuchCode()
or you could do
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode() {
// put new code here
}
}
which will allow you to run MyOwnClass->WithWayTooMuchCode() and will ONLY run the "new code", not the "100 lines".
Finally you could do
class MyOwnClass extends BaseClass {
public function WithWayTooMuchCode() {
parent::WithWayTooMuchCode();
// Do more processing
}
}
which will allow you to run MyOwnClass->WithWayTooMuchCode() will run the "100 lines of code" AND the new code. You can put the parent before/after/during your new code, so you can tailor it as required
In addition to the other answers I should point out that this problem can be addressed by events. They are a way to determine points in a class where you can add your own functionality from outside. If you have control over the codebase and the time/inclination you might want to consider implementing this functionality. Unfortunately PHP doesn't support them directly in the way that, say, C# does so you'd have to do the work.
If you only have this issue in a single place I doubt you should bother, but if it's becoming a pattern you might want to consider this approach.
I have a scenario where I'm trying to incorporate several people's PHP work, some of it OOP and some not. I want to pull a library file of functions into a class and have those functions be available to other files that reference the class. I know I can just call the library functions directly, but then I would have to update all of the dependent files to do likewise. Example:
class do_something {
function test_state() {
...
}
if ($this->test_state($var)) {
...
}
}
Where test_state() is identical to the same-named function in the library file, making for redundant code to keep sync'd. That can be changed to:
class do_something {
if (test_state($var)) {
...
}
}
But that creates the aforementioned problem of $this->test_state() not being available to files dependent on the class. What I'd like to be able to do is something like:
class do_something {
public function test_state() = test_state();
if ($this->test_state($var)) {
...
}
}
Obviously, that's a very rough and incorrect example of what I'm trying to do... Is there any way in OOP to make that sort of reassignment, making the method of the same name as the function available within the class?
You can use a workaround to simulate this. In fact you would often want this approach to bolt on closures to objects in PHP. It leverages the magic __call method in PHP to redirect method calls to ordinary functions (beware: no $this available).
class do_something {
function __call($func, $args) {
if (isset($this->$func) && is_callable($this->$func)) {
return call_user_func_array($this->$func, $args);
}
}
}
Then you can "register" functions that you want to allow (or closures) with a simple assignment:
$do_something->function_name = "global_function_name";
$do_something->or_even = array("other_class", "method");
But again, this doesn't make them proper methods as such.
You'd create your base utility class, then extend it. See PHP's manual entry for inheritance for the details. I'm not saying this is the best solution for your exact situation, but I think it answers the question you were trying to get at.
What you're asking for isn't possible directly, but can be faked with a quick (horrible) hack:
class do_something {
public function test_state($param) {
return test_state($param);
}
...
$this->test_state($param);
...
}
Good luck with refactoring!
I'm a big fan of OOP in php, but i feel like defining class methods gets disorganized so fast. I have a pretty good background in OOP in C++, and i am pretty comfortable with how it is handled there, and am curious if there are ways to do it similarly in php.
To be more specific, here is what i mean. I like how in C++ you can define a class header (myclass.h) and then define the actual details of the functions in the implementation file (myclass.cc). Ive found that this can easily be replicated using interfaces in php, but i havent found a good solution for the following:
I like to organize my code in C++ in different files based on how they are accessed, so for example, public methods that can be called outside of the class would be in 1 place, and private methods would be organized somewhere else - this is personal preference.
Ive tried to define class methods in php like:
private function MyPHPClass::myFunction(){ }
when the definition isnt directly inside the class block( { } ), but i havent had any success doing this.
Ive been through all of the pages on php.net, but couldnt find anything like this. Im assuming that there is no support for something like this, but thought i would ask anyway.
thanks
You can't do this. The class declarations are Java-like.
You have to put everything in one file or, at minimum, have some helper classes -- be they only static methods to which you forward or calls or with you deferring some implementation to encapsulated objects. You can also use the __call and __callstatic magic methods to reduce the size of your stubs, but that only works for public methods and I would recommend that you avoid magic methods.
EDI2: As RobertPitt pointed in a comment, you should consider alternative strategies that divide the functionality between several classes. It has the added advantage that it can make your code more decoupled. If you need, you can still unify the functionality of the several classes behind a façade.
EDIT: By using magic methods, I mean something like this:
class MyClassHelper {
public function method_one(array $args) {
...
}
public function method_two(array $args) {
...
}
}
class MyClass {
/**
* #var MyClassHelper
*/
private $helper;
private static $ALLOWED_METHODS = array("method_one" => NULL,
"method_two" => NULL);
public function __call($name, $arguments) {
$name = strtolower($name);
if (array_key_exists($name, self::$ALLOWED_METHODS) {
$helper->$name($arguments);
}
else
throw new Exception(...);
}
}
I should recommend that you avoid this, there are many pitfalls to this (handling of references, no code completion).
Im not really a C++ / C# Programmer but interfaces in php i can give you an exampe to see if this helps.
Interface
interface IDatabase
{
public function connect($dns = '');
public function disconnect($flushCache = false); //Do not use braces, Code free in interfaces
}
Database abstract base class
abstract class Database
{
//Some driver logic here to laod mysql,oracle etc
}
MySql Driver
class DBDriver_MySQl extends Database implements IDatabase
{
public function connect($dns = '')
{
//Connection logic.
}
public function disconnect($flushDns)
{
//Disconnect Login
}
}
Hope this is what your looking for.