avoiding long class constants as parameters - PHP - php

example:
class Vendor_ClassName_Helper {
CONST FIRST_OPTION = 1;
CONST SECOND_OPTION = 2;
public function __construct($option, $otherArgument) {
}
}
client code:
$obj = new Vendor_ClassName_Helper(Vendor_ClassName_Helper::FIRST_OPTION, $var);
Any good ways to avoid the long lines (and this is a rather short example)? Maybe other ways to implement the same?

I think clarity is better than short code. You can try to think of different words of expressing the same or different form. For your example, it doesn't seem very bad as Omega pointed out, and his method of splitting declaration on multiple lines is good as well.
Here's another trick: Depending on what your option constants do, you may want to employ a factory method instead of the new-keyword.
For example,
class Example {
private function __construct() { }
public static method createA(..) {
//configure for mode A
$cls = new self;
return $cls;
}
public static method createB(..) {
//configure for mode B
$cls = new self;
return $cls;
}
}
$x = Example::createA();

I avoid long lines and improve readability in most languages by breaking up the parameters into their own kind of block...
$obj = new Vendor_ClassName_Helper(
Vendor_ClassName_Helper::FIRST_OPTION,
$var
);
But two options doesn't always warrant it in my opinion. Static constants unfortunately can't really be changed and you do of course want them to remain descriptive.
What you have here isn't so bad :)

If you're passing a constant to the constructor, it would suggest that you should create subclasses instead:
class Vendor_ClassName_Helper {
public function __construct($otherArgument) {
}
}
class Vendor_ClassName_Helper_First extends Vendor_ClassName_Helper {
}
class Vendor_ClassName_Helper_Second extends Vendor_ClassName_Helper {
}

without using shorter name for class or constant's names (and making your code impossible to understand, which is something you definitly don't want), no, I don't think there is a way -- at least, not in PHP < 5.3
PHP 5.3 adds namespaces to PHP ; with those, you might be able to come to something shorter / better ; but it means using PHP 5.3, which is not proposed by many hosting companies (5.3.0 was release at the end of june this year, so it might be a while before it's available averywhere...)
For more informations about namespaces in PHP (and to cite only a couple of links) :
the manual
some articles on sitepoint
Migrating OOP Libraries and Frameworks to PHP 5.3 might interest you too

I think there isn't a better way (there isn't a dynamic way):
class LongClassName
{
const B = 3;
}
class LCN
{
const B = LongClassName::B;
}
echo LCN::B;

Related

PHP Classes containing only constants

First of all: I tried to google it, but I mostly only found discussions about how to define arrays in constants and other unrelated information.
I have a question regarding a solution to make my code more readable (and pretty) that just occured to me. Basically I have most functions return a status code that indicates success or, in case something went wrong, an error code. For this, I made a class called "StatusCode" that contains only constants, like so:
<?php
class StatusCode {
const success = 0;
const badArgument = -1;
const badQuery = -2;
const outOfMana = -3; //Really just for demonstration purposes
...
}
The purpose is to make magic numbers disappear from my code and make it clear what went wrong without having to look for an explaination somewhere:
if (mana > 10) {
//Do some magic
return StatusCode::success;
}
else {
//Oh god this is not good!
return StatusCode::outOfMana;
}
It should also eliminate the possibility of accidently using duplicate error codes.
I'm pretty sure this adds a minor overhead to my application, but has made my code easier to understand in return. Is there some earth shattering reason not to do this? Maybe an even better way to go about it?
(I have avoided the define(CONSTANT, "value") approach because it seems less pretty and it's a hassle to write on my German keyboard :))
In Java and other languages this is a commonly used way to namespace constants to avoid naming collisions. See here;
The way that I would implement such a class is like this"
// make this final so no one can extend it
final class Errors{
const SUCCESS = 0;
const BAD_ARGUMENT = -1;
const BAD_QUERY = -2;
const OUT_OF_MANA = -3;
// make this private so noone can make one
private function __construct(){
// throw an exception if someone can get in here (I'm paranoid)
throw new Exception("Can't get an instance of Errors");
}
}
This has the advantage of namespacing and grouping constants. You can use reflection on that class to iterate over defined constants, which allows you, for example, to validate that a value is a value of a certain constant group (enabling a poor man's constant type hinting).
The disadvantage is that you're kind of abusing a class (though only slightly). Purists may not like that. Constants which are not used in the same class should be global constants; you can even namespace them into something like \StatusCodes\SUCCESS in PHP 5.3+.
The choice is yours, really.
Creating an static class will solve your problem and avoid creating multiple instances of StatusCode
Namespaces can be used if you think your application can have multiple StatusCode classes but still the StatusCode will be static.
If you want to use singleton pattern this will work too
Choice is yours!
You can use an interface, so an instance cannot be created:
interface StatusCode {
public const success = 0;
public const badArgument = -1;
public const badQuery = -2;
public const outOfMana = -3;
}

Way to change results of object's methods

I was trying to find a way to execute some code to alter the results of an objects methods without actually touching the object's code. One way I came up is using a decorator:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
That way it will work properly but it has one disadvantage which makes it unusable for me right now - it would require replacing all lines with new Test() with new Decorator(new Test()) and this is exactly what I would like to avoid - lots of meddling with the existing code. Maybe something I could do in the base class?
One does not simply overload stuff in PHP. So what you want cannot be done. But the fact that you are in trouble now is a big tell your design is flawed. Or if it is not your code design the code you have to work with (I feel your pain).
If you cannot do what you want to do it is because you have tightly coupled your code. I.e. you make use of the new keyword in classes instead of injecting them (dependency injection) into the classes / methods that need it.
Besides not being able to easily swap classes you would also have a gard time easily testing your units because of the tight coupling.
UPDATE
For completeness (for possible future readers): if the specific class would have been namespaced and you were allowed to change the namespace you could have thought about changing the namespace. However this is not really good practice, because it may screw with for example autoloaders. An example of this would be PSR-0. But considering you cannot do this either way I don't see it is possible what you want. P.S. you should not really use this "solution".
UPDATE2
It looks like there has been some overload extension at some time (way way way back), but the only thing I have found about it is some bug report. And don't count on it still working now either way. ;-) There simply is no real overloading in PHP.
Found something (a dead project which doesn't work anymore that enables class overloading): http://pecl.php.net/package/runkit
Possibly another project (also dead of course): http://pecl.php.net/package/apd
I am not a PHP programmer, but I think that AOP is what you are looking for. You can try some frameworks, for example listed in this answer.
From the Wikipedia article on the decorator pattern:
Subclass the original "Decorator" class into a "Component" class
So I think you're supposed to keep the class to be decorated private and expose only the already-decorated class.

In PHP, how do I call a method top-down recursively through the hierarchy from a method in the grandest parent?

I have a class that is extended, and its children extended further, an arbitrary number of times. Each extension provides more functionality than its predecessor. The catch is, not all parameters can be provided at initialization time. It is complex enough to warrant passing more configuration options via methods, and then calling some sort of build() or configure() method to ready itself for operation.
The catch is, each class in the hierarchy needs a chance to configure itself, and it needs to cascade from the parent to all of the children.
I successfully do this below, but this solution requires that each class remember to call it's parent's method, otherwise it breaks. I want to remove that responsibility from those who might forget to do such.
How do I modify this code to achieve this?
<?php
class A {
function configure() {
print("I am A::configure() and provide basic functionality.<br/>\n");;
}
}
class B extends A {
function configure() {
parent::configure();
print("I am B::configure() and provide additional functionality.<br/>\n");
}
}
class C extends B {
function configure() {
parent::configure();
print("I am C::configure() and provide even more functionality.<br/>\n");
}
}
$c = new C;
$c->configure();
?>
Output:
I am A::configure() and provide basic functionality.
I am B::configure() and provide additional functionality.
I am C::configure() and provide even more functionality.
Thanks for your help! :)
Without claiming it's pretty, I'd suggest the following. I left out your configure() functions for brevity.
<?php
class A {
function configure_master() {
$init_class = get_class($this);
$ancestry = array();
while (! empty($init_class)) {
$ancestry[] = $init_class;
$init_class = get_parent_class($init_class);
}
for ($i = count($ancestry) - 1; $i >= 0; $i--) {
call_user_func(array($this, $ancestry[$i] . '::configure'));
}
}
}
$c = new C;
$c->configure_master();
I tested this, and it works. call_user_func($ancestry[$i] . '::configure') also works (at least in php 5.3, which is where I tested it), but it relies on the odd (to me) scoping of $this. I'm uncertain whether this is reliable or will carry forward into future versions. The version above "should be" more robust, given my limited knowledge.
If keeping the outside call as configure() is a requirement, I'd suggest renaming all your "configure()" methods to "configure_local()" or some such, and rename "configure_master()" to "configure()". In fact, that's what I'd do to start with, but that's a matter of personal taste.
If you need both the internal method and the external API to remain the same... Then you're stuck, since the base class method is overridden, but I'm sure you knew that.
An arbitrary amount of inheritance? I can't say that's a road I'd want to take, but if you must do so, you might be able to write some type of configure method in the base class that takes the calling (child) class as a parameter. That method would then determine the class type, walk the inheritance tree (pushing each parent class type onto a stack), and then simply run each configure method in succession. I think that the underlying principle might be called reflection, but I'm not sure. (edit: Even less sure, now. Definitely read about it before taking my word.)
The method in the base class might have to be static, though...
I believe that something like this would be possible, but I'm not really up to speed on PHP. I"ll do a little bit of searching and see if syntax and code allows this. Hopefully, though, you can use this idea.
This is the terrible pseudocode form of the idea that I have.
<?php
class A {
static function configure(class) {
//get qualified class name from argument
//get inheritance tree for qualified class name, push each tier into array
//loop: pop array, call configure method for each class in hierarchy
//this might possibly work?
}
}
class B extends A {
function configure() {
print("I am B::configure() and provide additional functionality.<br/>\n");
}
}
class C extends B {
function configure() {
print("I am C::configure() and provide additional functionality.<br/>\n");
}
}
$c = new C;
A::configure($c);
?>
Again, I'll take a look and see if anything in PHP could support this theory. In the meantime, I can live with a few downvotes.
Edit: Actually, this might not have to be static, as long as the method names don't overlap during inheritance. That actually might be a little more elegant, as the object could find its own class name and hierarchy by calling a master configure method.
How about this? (Forgive my PHP syntax if it is imperfect)
<?php
class MyBase {
private $_isChild = true;
public function __construct()
$this->_isChild = false;
}
public function behave() {
if $this->_isChild {
parent::behave();
}
self::doBehave();
}
protected function doBehave()
// do stuff here!
}
}
?>
In your child classes, just implement doBehave.
Max

Adapter pattern with static classes

I am looking for a good way to implement the Adaptor pattern with static classes in PHP 5.x.
One of the examples where I would like to use this, is as a counterpart to Python's os.path.join().
I would have two adaptees, a Windows and a Linux adaptee class.
I think it is reasonable, to implement these classes as static classes, because they have no "context". They do not need to store any state and creating an instance everytime I need one seems superfluous - therefore I am looking for a clean way to implement this.
Let's consider the following bogus implementation:
static public function join(){
$parts = func_get_args();
$joined = array(MY_MAGICALLY_PASSED_DEFAULT_PATH_PREFIX);
foreach($parts as $part){
$part = self::$adaptee->cleanPath($path);
if(self::$adaptee->isAbsolute($part)){
$joined = array($part);
}
else{
$joined[] = $part;
}
}
return implode(PATH_SEPARATOR, $joined);
}
The first thing you will notice is, that it assumes an initialized static member called adaptee which would hold the necessary, OS-dependent implementation details.
This requires me to have an arbitrarily named static constructor-like function, that I would call immediately after the declaration of the class. (Another thing that bothers me with this approach).
Of course, I could initialize a local $adaptee variable on each method call, but that seems like inappropriate and I would have to replicate that in each other static function that needs the adaptee.
Now... for PHP's class implemention detail: They are not first-class objects, so I couldn't just pass the class as an argument. In the example, it requires me to create the Adaptees as non-static (what is the term for this?) classes, then instantiate it and eventually assign it to the static $adaptee member variable of the Adapter class.
Maybe this is just this weird and completely subjective thought that I have... but I really feel that it is not appropriate to do it like this. Do you have any ideas about a better implementation?
One other idea that I've had is, to store the adaptee's class name instead, and use call_user_func instead, but I don't feel too comfortable using this approach.
Update
I may not have described this properly, so I will try to explain this in an update:
I am not looking on how to get the underlying Operating System, but I would like to have a neat way, for a static class to act differently depending on whether the OS is Linux, Windows, FreeBSD or something else.
I thought of the adaptor pattern, but since I don't have a static constructor, I cannot really initialize the class. One way would be to initialize it at the beginning of every public static method call (or just check whether it is initialized).
The other possibility would be, to create a static constructor-like method and simply call it right after the declaration. That might do the trick, but I am just wondering what other, possibly more elgeant methods there are, to achieving this.
As for my initial example:
It is supposed to be a utility function, it does not need to preserve state in any kind really, so I am not looking for a Path-Object of any sorts. What I would like, is a Path factory function, that returns a string, without having to differentiate between the different OSes every time when called. The "library"-thing led me to create a static class as pseudo-namespace for my related utility functions, and the different implementation details that need to be supported to the adaptor pattern. Now I am looking for an elegant way, to combine the two.
You'll shoot yourself in the foot when you make them static. You cannot inject static classes so you will always have coupling to the global scope and because you will hardcode static calls everywhere, maintaining them will become a nightmare. And you cannot mock them either (ok, PHPUnit can, but it only does to enable testing of code that otherwise would be untestable).
Just create an instance and use regular functions and save yourself some worries. There is no advantage in using statics. And the performance impact is utterly and totally negligible.
I'd probably create an interface for the adaptee and the adapters to implement
interface IPathAdapter
{
public function cleanPath($path);
public function isAbsolutePath($part);
// more …
}
and then do probably something like
class Path implements IPathAdapter
{
protected $_adapter;
public function __construct(IPathAdapter $adapter)
{
$this->_adapter = $adapter;
}
public function cleanPath($path)
{
$this->_adapter->cleanPath($part);
}
public function isAbsolutePath($part)
{
$this->_adapter->isAbsolutePath($part);
}
// more …
public function join(){
$parts = func_get_args();
$joined = array($this->getScriptPath());
foreach($parts as $part){
$part = $this->cleanPath($path);
if ($this->isAbsolutePath($part)){
$joined = array($part);
} else{
$joined[] = $part;
}
}
return implode($this->getPathSeparator(), $joined);
}
}
So when I want to use Path, I'd have to do
$path = new Path(new PathAdapter_Windows);
If you cannot inject the adapters, I'd probably go the route you already suggested and pass the Adapter class name as an argument to instantiate it from within Path then. Or I'd leave the detection of the appropriate adapter completely to the Path class, e.g. have it detect the OS and then instantiate what is needed.
If you want to autodetect, have a look at Does PHP have a function to detect the OS it's running on?. I'd probably write a separate class to handle the identification and then make it a dependency to the Path class, e.g.
public function __construct(IDetector $detector = NULL)
{
if($detector === NULL){
$detector = new OSDetector;
}
$this->_detector = $detector;
}
The reason I am injecting is because it will allow me to change the implementation, e.g. to mock the Detector in UnitTests but can also ignore to inject at runtime. It will use the default OSDetector then. With the detector, detect the OS and create an appropriate adapter somewhere in Path or in a dedicated Factory.
I think you can do this, you just have to put the namespace path into a global var, for example in composer autoload.php:
$GLOBALS['ADAPTED_CLASS_NAMESPACE'] = 'MyComponent\AdapterFoo\VendorBar';
I think it's a good approach in a context where you can't use dependency injection i.e in a entity for validation (we keep in mind that separated Validation classes are better).
<?php
namespace MyComponent;
use MyComponent\AdaptedInterface;
use ReflectionClass;
class Adapter
{
/**
* #var AdaptedInterface
*/
protected $adaptedClass;
public function __construct(AdaptedInterface $validator = null)
{
if (null == $validator && $this->validateClassPath($GLOBALS['ADAPTED_CLASS_NAMESPACE'])) {
$this->adaptedClass = new $GLOBALS['ADAPTED_CLASS_NAMESPACE'];
} else {
$this->adaptedClass = $validator;
}
}
protected function validateClassPath($classPath)
{
$reflection = new ReflectionClass($classPath);
if (!$reflection->implementsInterface(
'MyComponent\AdaptedInterface'
)) {
throw new \Exception('Your adapted class have not a valid class path :' . $classPath . 'given');
}
return true;
}
}
So anywhere:
(new Adapter())->foo($bar);

Is it possible to convert between classes with a common parent?

If I have two classes that each extend a common parent, is it possible to convert between them?
class Foo
{
public $bar;
}
class FooDatabase extends Foo
{
public function load() {}
public function save() {}
}
class FooFlatfile extends Foo
{
public function load() {}
public function save() {}
}
$foo = new FooDatabase;
$foo->bar = 'elf';
Using this code as an example, I want to convert $foo from an instance of FooDatabase to FooFlatfile, while retaining the value of the property bar.
Edit: I do realise that actually doing this isn't such a great idea in practice. Rather, I came across a situation in which this was a potential fix, and became curious about how it might be achieved.
This is possible although not advised. Take a look at A dark corner of PHP: class casting. Basically:
Serialize the class;
Change the class name in the serialized form; then
Deserialize it.
Yes, it's a hack.
The bigger question: is why do you want to do this? If you have the need to change class it's a very strong indicator that your object model is bad. It reminds me of the old examples of introductory OO they used to give:
Person class;
Salesman extends Person;
Manager extends Person.
which is a horrible example for the same reason: what if someone changes from a Salesman to a Manager? Compare that to the composition-based approach where Person has-a Job (where Manager and Salesman are instances or subclasses of Job). Much more sound approach.
Lastly, I'll add that if some code you can't change is forcing you to do this, you'd be best off using some sort of adapter or facade:
class A { ... }
class B {
public function asA() {
$ret = new A;
// configure;
return $ret;
}
...
}
Again this is much more sound than any sort of automatic property copying class changing process.
Can you accomplish what you need by creating a new one and copying the values over?
$foo2 = new FooFlatFile;
$foo2 = foo->bar;
If doesn't get done what you need, please give us more details.
Response to comment:
If you are planning on doing that often, it would be easy to create a member function to return all members in some sort of array or struct. However, at that point, you really need to ask yourself "why am I doing this?" The other responder is spot on in saying that if you are regularly wanting to do this, you have designed your classes very badly.
If you've got two classes you are wanting to switch between, remove what is separating them, and make one class. Either they are fundamentally the same, in which case you could get away with switching between them, but you would be far better served by making just one class.
Or they are fundamentally different from each other, in which case you still need two classes. If you have a database, and you're trying to turn it into a flat file, you need to have an export function translate the database into flat data. Dynamically changing classes would be like using Notepad to open up an Oracle file: it would not yield the data in a meaningful, usable manner. To go between them, you write 'export' and 'import' functions that use the same data structure as each other. You create a new one, export from the old, import into the new, and delete the old.
I'm frankly not sure what else to say, because I can't imagine a scenario where it would make sense to do this. If you could give more details about the background of what you're trying to solve, I could offer better advice.
You can do something like this, has some limitations (limits on types of constructors and can't copy private vars) but it can be made to work.
class Foo {
public $bar;
protected function convertTo($classname) {
$rc_other_class = new ReflectionClass($classname);
if ($rc_other_class->isSubclassOf(get_class())) {
// there's a limitation here in that the constructor can't take params
$other_class = new $classname();
$rc_this_class = new ReflectionClass(get_class());
$properties = $rc_this_class->getProperties();
foreach ($properties as $property) {
if (!$property->isStatic() &&
$property->getDeclaringClass()->getName() == get_class()) {
$property = $property->getName();
if (property_exists($this, $property)) {
// this will throw if you try to copy a private var, add a filter to
// getProperties to prevent this but you probably want the error
$other_class->$property = $this->$property;
}
}
}
} else {
return false;
}
}
}

Categories