I want to use the same piece of code for managing multiple entities but it might be a little different depending if it has some method or not. Thats why I need to check if object has method by name. Is there any way to do that?
You can simply use is_callable:
if (is_callable([$entity, 'methodName']))
doSomething();
A cleaner approach is to check for the class of an object with instanceof. Because methods will come and go, but the character of an object is determined by its class:
if ($entity instanceof \Some\Bundle\Entity\Class)
doSomething();
This has nothing to do with Symfony, it's basic PHP thing: use method_exists PHP function.
bool method_exists ( mixed $object , string $method_name )
PHP Docs
While this is a perfectly fine way to go around it, you might want to look into interfaces as an alternative: PHP Interfaces
If you do decide to use them, you can just check if object is an instance of your interface:
interface MyAwesomeInterface
{
public function myFunction();
}
if ($myObject instanceof MyAwesomeInterface) {
$myObject->myFunction();
}
Related
I am creating a collection class and would like it to be drop-in-replacement for arrays, which I use currently.
How to create a class which could be casted to boolean, so the class can be truthy or falsy?
A simple test shows that an object of empty class is truthy:
class boolClass {}
$obj = new boolClass();
var_dump( (bool)$obj);
//prints
//bool(true)
But I need to decide if my class is truthy or falsy. Is there eny way to tell the PHP engine how to cast my class to boolean? Like I could do with __toString()?
Background:
Lets say I write a class like this (it's an example only):
class MyCollection implements ArrayAccess, Iterator {
//...
}
I heavily use this patterns currently:
$var = array();
if (empty($var)) {
//array is empty, (or there is no array at all)
// I do something here
}
I would like that to look like:
$var = new MyCollection(array());
and keep the rest unchanged. But the $var containing MyCollection is always truthy so I would need to all the conditions to:
if ($var->isEmpty()) {
//...
}
But this is unacceptable, as my codebase have many megabytes.
Any solution here?
After much angst, disappointment, and hacking - I believe I have found a solution. The solution doesn't call for any extensions; it can be implemented with a very small amount of PHP boilerplate. However, before implementing this solution yourself, please take note that this is - in fact - a HUGE hack. That being said, here is what I discovered:
Frustrated, I spent some time looking over the PHP documentation for Booleans. While user-created classes are simply denied the ability to be cast as a boolean, one class - oddly enough - was afforded the capability. The astute reader would notice that this class is none other than the built-in SimpleXmlElement. By process of deduction, it seems fair to assume that any subclass of SimpleXmlElement would also inherit its unique boolean-casting capability. While, in theory this approach seems valid, the magic surrounding SimpleXmlElement also takes away from the utility of this approach. To understand why this is, consider this example:
class Truthy extends SimpleXmlElement { }
Truthy is a subclass of SimpleXmlElement, so we should be able to test if its special boolean-casting property was inherited:
$true = new Truthy('<true>1</true>'); // XML with content eval's to TRUE
if ($true) echo 'boolean casting is happening!';
$false = new Truthy('<false></false>'); // empty XML eval's to FALSE
if (!$false) echo 'this is totally useful!';
Indeed, the boolean-casting property afforded to SimpleXmlElement is inherited by Truthy. However, this syntax is clumsy, and it is highly unlikely that one would get much utility out of this class (at least when compared to using SimpleXmlElement natively). This scenario is where the problems start to come up:
$false = new Truthy('<false></false>'); // empty XML eval's to FALSE
$false->reason = 'because I said so'; // some extra info to explain why it's false
if (!$false) echo 'why is this not false anymore?!?';
else echo 'because SimpleXMLElements are magical!';
As you can see, trying to set a property on our subclass immediately breaks the utility we get from the inherited boolean-casting. Unfortunately for us, the SimpleXmlElement has another magical feature that breaks our convention. Apparently, when you set a property of a SimpleXmlElement, it modifies the XML! See for yourself:
$xml = new SimpleXmlElement('<element></element>');
$xml->test = 'content';
echo $xml->asXML(); // <element><test>content</test></element>
Well there goes any utility we would get from subclassing SimpleXmlElement! Thankfully, after much hacking, I found a way to save information into this subclass, without breaking the boolean casting magic: comments!
$false = new Truthy('<!-- hello world! --><false></false>');
if (!$false) echo 'Great Scott! It worked!';
Progress! We were able to get useful information into this class without breaking boolean-casting! Ok, now all we need to do is clean it up, here is my final implementation:
class Truthy extends SimpleXMLElement {
public function data() {
preg_match("#<!\-\-(.+?)\-\->#", $this->asXML(), $matches);
if (!$matches) return null;
return unserialize(html_entity_decode($matches[1]));
}
public static function create($boolean, Serializable $data = null) {
$xml = '<!--' . htmlentities(serialize($data)) . "-->";
$xml .= $boolean ? '<truthy>1</truthy>' : '<truthy/>';
return new Truthy($xml);
}
}
To remove some of the clumsiness, I added a public static factory method. Now we can create a Truthy object without worrying about the implementation details. The factory lets the caller define any arbitrary set of data, as well as a boolean casting. The data method can then be called at a later time to retrieve a read-only copy of this data:
$false = Truthy::create(false, array('reason' => 'because I said so!'));
if (!$false) {
$data = $false->data();
echo 'The reason this was false was ' . $data['reason'];
}
There you have it! A totally hacky (but usable) way to do boolean-casting in user-defined classes. Please don't sue me if you use this in production code and it blows up.
On this page, the magic methods that you can define for your classes are enumerated.
http://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring
You demonstrate that you already know about __toString().
Unfortunately, there is no magic method listed there that does what you are asking. So, I think for now your only option is to define a method and call that method explicitly.
You can take a look at the PHP operator extension which you can use to overload many operators including == and ===. With this extension, you should be theoretically able to write a class comparable to boolean values like this:
if($object == true)
You cannot.
In PHP an object when cast to bool always produces true. There is no way of changing that.
If you have a code size of "many megabytes" the issue is probably not that your naming scheme is too verbose. I would instead look for duplication and try to abstract code.
OTOH, why is the size of the code a big issue? Try to minimize the code you are including each time php runs. Stray code that isn't used makes no difference. If you have to include a lot of code, consider using caching software, such as MMCache.
And to answer your original question, AFAIK there is no way to add type coercion to PHP classes. an instance will always evaluate to true.
If you don't want to implement your own method you could hack your way into __toString, like this:
class foo
{
public function __toString()
{
return strval(false);
}
}
$foo = new foo();
if (strval($foo) == false) // non-strict comparison
{
echo '$foo is falsy';
}
echo (bool) strval($foo); // false
Well, there is __invoke method which seems close to your intention:
class boolClass {
public function __invoke() {
return true;
}
}
$obj = new boolClass();
var_dump( (bool)$obj());
//prints
//bool(true)
I'd like to have a generic wrapper-class for some classes to intercept and manipulate some of the method-calls. Method-call-forwarding, intercepting, no problem so far. But after thinking a while, i found a problem for which i have no solution: I'm using the built-in instanceof-operator everywhere in my application. Of course this won't work anymore, because the wrapper isn't an instance of the class inside it. I would like to continue using the operator and not to replace it with an other function.
Is there a way to implement a workaround for this problem? How does this operator work? Does it call a core-function of the classes which i am probably able to overwrite in my wrapper?
I know that this would not be a really "clean" solution to manipulate this operator, but i think this would be the simplest solution for me. And as we know, there are many things in PHP which are not that clean... :-)
Thanks for your answers, Ben
I don't know is it possible to trick a instanceof operator in way you want (recognize a class as subclass if it is not) but I think I found a solution that may suit your needs. If I understand correctly your problem then you simply want to inject some methods in any class with minimal changes in your whole code.
I think the best way to prepare a solution in this case is using traits (described here). With traits you can add methods to any class without direct inheritance and it can overwrite methods from base class. For overwriting method with traits you of course need a subclasses but they can be created dynamically. I don't know anything about your wrapping process but in my solution I used a special class for it. Lets look at my solution:
namespace someNameSpace;
//this is one of your class that you want to wrap - it can be declare under some other namespace if you need
class yourBaseClass { }
//your wrapper class as a trait
trait yourWrapper { }
//class for wrapping any object
class ObjectWrapperClass
{
//method for change object class (described on http://stackoverflow.com/a/3243949/4662836)
protected static function objectToObject($instance, $className)
{
return unserialize(sprintf('O:%d:"%s"%s', strlen($className), $className, strstr(strstr(serialize($instance), '"'), ':')));
}
//wrapping method
//$object is a object to be wrapped
//$wrapper is a full name of the wrapper trait
public static function wrap($object, $wrapper)
{
//take some information about the object to be wrapped
$reflection = new \ReflectionClass($object);
$baseClass = $reflection->getShortName();
$namespace = $reflection->getNamespaceName();
//perpare the name of the new wrapped class
$newClassName = "{$baseClass}Wrapped";
//if new wrapped class has not been declared before we need to do it now
if (!class_exists($newClassName)) {
//prepare a code of the wrapping class that inject trait
$newClassCode = "namespace {$namespace} { class {$newClassName} extends {$baseClass} { use {$wrapper}; } }";
//run the prepared code
eval($newClassCode);
}
//change the object class and return it
return self::objectToObject($object, $namespace . '\\' . $newClassName);
}
}
//lets test this solution
$originalObject = new yourBaseClass();
$wrappedObject = ObjectWrapperClass::wrap($originalObject, 'yourWrapper');
if ($wrappedObject instanceof yourBaseClass) {
echo 'It is working';
}
As you can see everything is happens during wrapping process.
If you have more wrappers then you can prepare the new wrapped class name in other way (for example to be corelated with wrapper name).
Probably I can describe a solution for your needs. (disclaimer: I'm author of Go! AOP Framework) From your description it looks like you want to dynamically add additional logic to your methods without touching the class. If I'm right, then you could have a look at Aspect-Oriented Paradigm that introduces a concept of interceptors for your source code, what is more important - your original classes will be untouched.
To have an idea, how this can be applied to your code, you could also have a look at my article http://go.aopphp.com/blog/2014/10/19/caching-like-a-pro/ that highlights all advantages and disadvantages of classical object-oriented patterns like decorator, proxy. I can make a conclusion, that all interceptors can not be extracted into separate modules in object-oriented way because of essential complexity and limitations of PHP for solving cross-cutting concerns. AOP extends traditional OOP model, so it will be possible to extract interceptors (called advices) into separate classes (called aspects).
Brilliant feature of AOP is that it keeps your original class names and this means that you shouldn't change typehints in your code or even hijack a instanceof operator. You will get your class with additional logic.
Not possible at all. Actually, maybe in the future: https://bugs.php.net/bug.php?id=71352
Use an interface instead of the concrete class. Apply the interface to Wrapper and Concrete Class.
See http://de3.php.net/manual/en/language.oop5.interfaces.php
Have a look at decorator pattern. If your wrapper/wrapped classes implement the same interface, you can do everything elegantly (and use instanceof interface throughout the code).
Is there a way to implement a workaround for this problem? How does this operator work? Does it call a core-function of the classes which i am probably able to overwrite in my wrapper?
You cannot manipulate instanceof operator. Since you were interested how instanceof operator is implemented, here is a PHP representation of original C code:
class php_class {
public $interfaces = array(); // array of php_class objects (php classes can implement more than one interface)
public $parent = null; // php_class object (php classes can only extend one class)
}
function instanceof_operator($implementation, $abstraction) {
// forward recursion (iterates recursively through interfaces until a match is found)
for($i=0; $i<count($implementation->interfaces); $i++) {
if(instanceof_operator($implementation->interfaces[$i], $abstraction)) {
return true;
}
}
// backward recursion (iterates recursively through parents until a match is found)
while($implementation!=null) {
if($implementation == $abstraction) {
return true;
}
$implementation = $implementation->parent;
}
// no match was found
return false;
}
Whenever you declare a class to implement/extend an interface/class, imagine an entry is deposited on $interfaces or $parent fields that remains immutable until script terminates.
Even though there's some discussions regarding this issue I wanted to check on certain example what would be the best approach.
Instead of using existing solutions I created my own persistence layer (like many do)
So my approach is also in question here.
For every table in db I have model class that has appropriate getters and setters and some mandatory methods. I also created only one generic DAO class that handles all types of model objects.
So, for example to save any model object I instantiate genericDAO class and call save method that I pass model object as attribute.
Problem is that in runtime genericDAO class doesn't know whitch model object it gets and what methods (getters and setters) exist in it, so I need to call mandatory model class method that retrieves list of attributes as multiple string array.
For example for every attribute there's array(table_column_name,attribute_name,is_string).
When I call save function it looks like this:
public function save(&$VO) {
$paramArray = $VO->getParamArray();//get array of attributes
$paramIdArray = $paramArray[0]; //first attribute is always id
/*create and execute getId() and store value into $void to check if it's save or update*/
eval('$voId = $VO->get'.ucfirst($paramIdArray[1]).'();');
...
Currently I'm using eval to execute those methods, but as it is well known eval is very slow.
I'm thinking of changing that into call_user_func method
Something like:
$voId = call_user_func(array($VO, 'get'.ucfirst($paramIdArray[1])));
But also there's other solutions. I can maybe use something like this $method = 'get'.ucfirst($paramIdArray[1]));
$voId = $VO->$method();
or else
$method = 'get'.ucfirst($paramIdArray[1]));
$voId = $VO->{$method}();
What would be the best way?
First of all, there's no need to pass references like you are doing. You should give this a read to try to understand how PHP handles object references.
So public function save(&$VO) { should become public function save($VO) {.
Second, there is no need to use eval (in fact, it's better not to because of speed, debugability, etc). You can't stack-trace an eval call like you can a dynamic one.
Third, call_user_func is all but useless since PHP supports dynamic variable functions. Instead of call_user_func(array($obj, $method), $arg1), just call $obj->$foo($arg1). The call_user_func_array function is still useful since it supports variable length arguments and supports passing references.
So, ultimately, I would suggest this:
$method = 'get' . ucfirst($paramIdArray[1]);
$voId = $VO->$method();
Note that there's no need to call method_exists, since it may be callable and not exist due to __get magic method support...
I normally would use:
$method = 'get'.ucfirst($attribute);
if(method_exists($obj, $method){
$obj->$method();
}
But unless there is a very good reason i would just return a key => value array from getParamArray. And operate on that instead of using the getters...
Am I missing something or there really is no support for generic object type hinting in PHP 5.x?
I find it really strange that hinting arrays is supported while hinting objects is not, at least not out of the box.
I'd like to have something like this:
function foo(object $o)
Just as we have:
function foo(array $o)
Example of possible use: methods of an objects collection class.
Workaround: using an interface "Object" implemented by all classes or extending all classes from a generic class "Object" and writing something like this:
function foo(Object $o)
Well, that just ain't cute.
Using stdClass as the type hint doesn't work:
Catchable fatal error: Argument 1
passed to c::add() must be an instance
of stdClass, instance of b given
Since type hinting should make the client code adapt to your API, your solution with accepting interfaces seems just about right.
Look at it this way: yourMethod(array $input) gives yourMethod() an array to use, thereby you know exactly which native functions that applies and can be used by yourMethod().
If you specify your method like: yourSecondMethod(yourInterface $input) you'd also know which methods that can be applied to $input since you know about/can lookup which set of rules that accompanies the interface yourInterface.
In your case, accepting any object seems wrong, because you don't have any way of knowing which methods to use on the input. Example:
function foo(Object $o) {
return $o->thisMethodMayOrMayNotExist();
}
(Not implying that syntax is valid)
No, it can't be done. I wasn't missing anything.
I feel your pain, but I can't find a way of doing it either.
Despite what a number of other posters have said, it makes perfect sense to want 'Object' type hinting; they just haven't considered a scenario that requires it.
I am trying to do some work with the reflection API, and because of that I don't care what class is passed to my function. All I care is that it's an object. I don't want an int, a float, a string or an array. I want an object. Given that reflection is now part of PHP, it definitely makes sense to have object type hinting.
You cannot just say "object" when type casting an object... you must define WHICH object you are expecting.
From: http://php.net/manual/en/language.oop5.typehinting.php
class MyClass
{
/**
* A test function
*
* First parameter must be an object of type OtherClass
*/
public function test(OtherClass $otherclass) {
echo $otherclass->var;
}
/**
* Another test function
*
* First parameter must be an array
*/
public function test_array(array $input_array) {
print_r($input_array);
}
}
// Another example class
class OtherClass {
public $var = 'Hello World';
}
The best way to enforce this would be to create a degenerate interface called Object. A degenerate interface means it has no defined methods.
interface Object {
// leave blank
}
Then in your base classes, you can implement Object.
class SomeBase implements Object {
// your implementation
}
You can now call your function as you wanted to
function myFunc (Object $obj);
myFunc($someBase);
If you pass any object which inherits from your Object interface, this type hint will pass. If you pass in an array, int, string etc, the type hint will fail.
Here's another example where it is required...
I've created a class to implement record locking. Records being one of a number of different object types. The locking class has several methods which require an object (the one to be locked) but don't care what type of object it is.
E.g.
public static function lockRecord($record, User $user, $timeout=null)
{
if(!is_object($record)) throw new \InvalidException("Argument 1 must be an object.");
$lock=new Lock();
$lock->setRecord($record);
$lock->setUser($user);
$lock->setTimeout($timeout);
$lock->activate();
return($lock);
}
You'll see that my solution was to use is_object() and throw an exception, but I'd far rather be able to do it with type hinting instead.
Ok, so not the end of the world, but I think it's a shame.
Objects in php are not subclasses of some StdClass or Object as it is in other OOP languages. So there is no way of type hinting the object. But I see your point because sometimes you want to make sure that the Object is being passed, so I guess the only way is to raise the issue manually.
public function yourFunction($object){
if(is_object($object)){
//TODO: do something
}else{
throw new InvalidArgumentException;
}
}
As of php 5.4 there is also a type hint callable.
See php manual http://php.net/manual/en/language.types.callable.php
Why would you want to hint object when you can hint an actual class name instead - this would be much more useful. Also remember that you can't hint int,float, bool, string or resource either.
public static function cloneObject($source)
{
if ($source === null)
{
return null;
}
return unserialize(serialize($source));
}
This is where you would need it.
Since PHP 7.2 you can finally declare the way you wanted:
function functionName(object $someObjectVariable)
See the table named "Valid types" at this page:
https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration
I've always worry about calling methods by referencing them via strings.
Basically in my current scenario, I use static data mapper methods to create and return an array of data model objects (eg. SomeDataMapper::getAll(1234)). Models follow the Active Record design pattern. In some cases, there could be hundreds of records returned, and I don't want to put everything into memory all at once. So, I am using an Iterator to page through the records, as follows
$Iterator = new DataMapperIterator('SomeDataMapper', 'getAll', array(1234));
while ($Iterator->hasNext()) {
$data = $Iterator->next();
}
Is that a good way of doing this? Is it a bad idea to pass as strings the name of the mapper class and the method? I worry that this idea is not portable to other languages. Is this generally true for languages like Ruby and Python? If so, can anyone recommend a good alternative?
FYI, for future peoples' refernce, I call the method like this:
$method = new ReflectionMethod($className, $methodName);
$returnValue = $method->invokeArgs(null, $parameters);
This is essentially a version of the factory pattern - Using strings to create a object instance.
However, I question the design idea of using an iterator to control the paging of data - that's not really the purpose of an iterator. Unless we just have name confusion, but I'd probably prefer to see something like this.
$pager = new DataMapperPager( 'SomeDataMapper', 'someMethod', array(1234) );
$pager->setPageNum( 1 );
$pager->setPageSize( 10 );
$rows = $pager->getResults();
foreach ( $rows as $row )
{
// whatever
}
Of course, DataMapperPager::getResults() could return an iterator or whatever you'd want.
It is an acceptable way of doing it. Both Python and Ruby support it and thus should be portable. Python can do it as easily as PHP can, however Ruby has a little more to it. In Python at least, it is useful for when the particular class you're referencing has not yet been imported nor seen yet in the file (i.e. the class is found lower in the same file as where you're trying to reference it.)
Getting a class object from a string in Ruby: http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
PHP doesn't really support the passing of functions any other way. All dynamic method invocation functions in PHP take what they call a "callback" - see http://us.php.net/manual/en/language.pseudo-types.php#language.types.callback for documentation on that. As you'll see, they're just string or arrays of strings in different usage patterns, so you're not far off.
There are however, design patterns that work around this. For instance, you could define a DataMapper interface that all of your mapper classes must implement. Then, instead of passing in the class and method as string, you could pass the mapper instance to your iterator and since it requires the interface it could call the interface methods directly.
pseudocode:
interface DataMapper
{
public function mapData($data);
}
class DataMapperIterator ...
{
public function __construct(DataMapper $mapper, ...)
{
...
}
...
public function next()
{
... now we can call the method explicitly because of interface ...
$this->mapper->mapData($data);
}
}
class DataMapperImplemenation implements DataMapper
{
...
public function mapData($data)
{
...
}
...
}
Calling methods by name with passed in strings isn't horrible, there's probably only a performance penalty in that the bytecode generated can't be as optimized - there will always be a symbol lookup - but I doubt you'll notice this much.