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;
}
Related
At the moment i am trying to create a helper class for our template designers, that have minimal PHP knowledge, so i would like to make it as fool proof as possible.
In that process i have stumbled upon a question i never really considered before:
How does one check to see if a parameter to a method call is the value of a defined class constant?
I can think of several ways to do it using reflection or the like, but was wondering if there is some way more simple that i have overlooked.
Taking a class like the following:
class Foo{
const TYPE_A = 'A';
const TYPE_B = 'B';
const TYPE_C = 'C';
public static function doSomething($type){
//Check to see if $type is indeed a class constant
}
}
//This would work
Foo::doSomething(Foo::TYPE_A);
Foo::doSomething(Foo::TYPE_B);
Foo::doSomething(Foo::TYPE_C);
Foo::doSomething('A');
Foo::doSomething('B');
Foo::doSomething('C');
//This should fail
Foo::doSomething('BAR');
Besides using reflection i could just use a private array or the like, but that would really defeat the purpose of the constants, or require that data is updated several places.
Does not seem to be possible without reflection or custom hacks so i am closing this
You can check if the constant is defined with http://php.net/manual/en/function.defined.php
public static function doSomething($type){
if (defined('self::' . $type)) {
// do someting
}
}
I've read what I could find on this issue, but I'm pretty much baffled at the lack of alternatives. If you have an OOP project in PHP, using consts is as ugly as it can get. Here's the problem:
class Invisible {
CONST youCantSeeMe = "";
}
class Ugly {
$invisible;
static $invisible2;
function __construct() {
$this->$invisible = new Invisible();
self::$invisible2 = New Invisible();
$this->invisible::youCantSeeMe; (illegal, crashes project)
self::$invisible2::youCantSeeMe; (illegal, crashes project)
}
function uglyFunction() {
//this is the only, ugly way to do it
$invisible = $this->invisible;
$invisible::youCantSeeMe (this works)
}
}
The only other way I've found around it, is to make a public get for each const you have (cumbersome, waste of time), or with a magic __get using a reflection class (expensive).
There HAS to be a better way than these options?
I believe your complaint really has to do with incomplete dereferencing support.
:: only accepts simple reference variables on the left hand side
This is fixed in the Uniform Variable Syntax RFC which is implemented in PHP 7.
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.
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;
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;
}
}
}