My particular scenario involves doing some text transformation using regular expressions within a private method. The private method calls preg_replace_callback, but is seems that callbacks need to be public on objects, so I'm stuck breaking out of the private world and exposing implementation details when I'd rather not.
So, in a nutshell: Can I use an instance method as a callback without losing encapsulation?
Thanks.
Yes, it seems you can:
<?php
//this works
class a {
private function replaceCallback($m) { return 'replaced'; }
public function test() {
$str = " test test ";
$result = preg_replace_callback('/test/', array($this, 'replaceCallback'), $str);
echo $result;
}
}
$a = new a();
$a->test();
//this doesn't work
$result = preg_replace_callback('/test/', array(new a(), 'replaceCallback'), ' test test ');
echo $result;
So it seems that preg_replace_callback(), or PHP's callback mechanism, is aware of the scope in which it was called.
Tested on 5.2.8
Can you create a separate helper class for text processing, and create the callback method within that class (it can be public there)? You can pass in a reference to the original class(object) if you need access to specific instance data.
The public interface to your main class remains consistent and clean, and you pull specific string processing out of a class it probably doesn't belong in anyway...
Can you not use protected? I'd need to know what the relationship of these two classes were in relation to each other to be more clear, but you should be able to extend the class and use the new protected methods you have inherited without making them public.
Hope this helps!
Cheers
Related
I have two classes that I use to access two different tables in my db. They both have a similar constructor that looks like that:
function __construct($db) {
$this->db = $db;
$userDAO = DAO_DBrecord::createUserDAO($this->db);
$this->userDAO = $userDAO;
}
The other class has the same constructor except that it uses createOtherTableDAO($this->db).
I am planning on having a couple other such classes, and it would be convenient if I could have them all inherit the same constructor, and pass createAppropriateTableDAO as an argument.
To clarify, in the first case above, createUserDAO($this->db) is a static function that calls a constructor in my DAO class. The function in the DAO looks as follows:
public static function createUserDAO($db) {
return new DAO_DBrecord($db, 'users');
}
I use this method to make sure the user model can only call a DAO on the users table.
I'm somewhat of a beginner, and I don't think I have ever seen anything like what I want.
Move the code to create the DAOs into a Factory and then inject the DAOs instead of hard coupling them into whatever these classes are supposed to represent. Or rather create the various Table Data Gateways ("classes that I use to access two different tables") as a whole in the Factory, e.g.
class TableDataGatewayFactory
…
public function create($gatewayName)
{
switch ($gatewayName) {
case 'user':
return new TableDataGateway(new UserDao($this->db)));
break;
default:
throw new Exception('No Gateway for $gatewayName');
}
}
}
As for $this->db, either pass that into the Factory via the ctor or move the creation into the Factory as well. It's somewhat doubled responsibility, but tolerable given that this Factory revolved around creating Database related collaborator graphs.
Apart from that: yes, call_user_func(array('ClassName', 'methodName')) would work. See the manual for
http://php.net/call_user_func and
http://php.net/manual/en/language.pseudo-types.php#language.types.callback
To answer your question first: No, you can't (without resorting to evilCode) pass a function name as a parameter.
But: What you want to archive is a poster-child-issue for an object oriented approach using inheritance.
You'd need a base-class:
class BaseClass
{
function __construct($db) {
$this->db = db;
}
}
and your implementations :
class MyClass extends BaseClass
{
function __construct($db) {
parent::__contruct($db);
$this->userDAO = DAO_DBrecord::createUserDAO($this->db);
}
}
Just for the record: the evilCode would have been
a) you could encapsulate your function in a create_function that can be used as an argument.
b) you could pass the function name as a string to your function and then pass it to eval in the receiving function.
But remember: When eval or create_function looks like the answer you're probably asking the wrong questions!
See: related question
There are several methods which you can use if you feel it necessary to pass the function name or indeed the function itself as a parameter of a function.
call_user_func($function,$args);
call_user_func is one of Php's native functions for invoking methods or functions which takes a function name and optional arguments parameter.
The functionality of call_user_func (when not pertaining to object methods) can be replicated without the using call_user_func using a variable with the string literal of the function name. For example:
function some_func()
{
echo "I'm a function!";
}
$function = "some_func";
$function(); /*Output: I'm a function!*/
And if you're feeling adventurous you can go a bit further and pass a closure / anonymous function as instead of the function name. For example:
$function = function()
{
echo "I'm another function!";
}
$function(); /*Output: I'm another function*/
You can achieve such behavior by using:
call_user_func
eval any literal
I am very new to OOP and very rusty on PHP. I was wondering if this is a valid method to call a function from a class?
class newclass {
public function testfunc {
return '1';
}
}
Could I call it like this:
echo testfunc->newclass();
or like this:
echo newclass()::testfunc;
I always see it defined in examples like below and it seemed like extra code?:
$this = new newclass();
$this->testfunc();
echo $this;
Any help would be greatly appreciated as I'm just starting to wrap my head around this OOP thing. If I'm out to lunch maybe someone could suggest a link to a really good guide for a true beginner in classes/OOP. Thanks!
Both ways work and have their use cases.
Your first case is a regular function call using an instance of a class, your second case is a call to a static function.
Static should be used with care and the use of it is very often a sign that refactoring/redesign is necessary.
The point of object oriented programming is to model the world by writing classes (blueprints) and then create as many independent instances of that class with the word new as needed. Each instance is a little organism with the DNA of the class and you can call the same class method on every single instance without influencing the other instances.
A static call however is not related to an instance of a class and therefore there is no object being used. It's a global call of some tool functionality and in fact breaks the idea of encapsulation.
So, I'm not saying there are no use cases for static classes and methods but they should be used with care.
new is the keyword to instantiate the class. If you want to use a method without an instance of the class, it should be a static method. to have a static method, declare the method as static.
class foo
{
public static function bar()
{
return 'hello!';
}
}
How to use it?
echo foo::bar(); //Will print hello
You could make testfunc static and call it like so:
class newclass{
public static function testfunc{
return '1';
}
}
echo newclass::testfunc();
There is nothing like this echo testfunc->newclass(); and doing it like
$class = new newclass();
echo $class->testfunc();
is the proper way to do it when the method is an instance method and not a static one. Note, there is no ability to reference $this within the static method.
You can create a static wrapper for the constructor which would allow for chaining method calls on the same line.
<?php
class ClassA {
static function create() { return new self(); }
function method1() { ... }
}
ClassA::create()->method1();
you can include the php file that contains your functions
<?php
//print.php
function printHello(){
echo "Hello world";
}
?>
then include it and call the function...
<?php
include "print.php";
printHello();
?>
As the title says, I'm wanting to create an instance of a class from within a static method of the same class. I've figured out so far is that I can by doing something like this:
class Foo{
public $val;
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Which therefore lets me do this.
$obj = Foo::bar("some variable");
Which is great.
So now the questions. Is there an easier way of doing this that I'm not aware of, or any shortcuts to achieving the same result? Are there any advantages or disadvantages of creating an instance in this fashion?
Thanks.
They way you're doing it is fine. There are a few other things that can make your life easier that you can do as well.
Don't hardcode the class name. If you're on 5.3+, use the keyword static. That way, if you extend the class, the new function can instantiate that one as well:
public static function bar($var) {
$obj = new static();
$obj->var = $var;
return $obj;
}
Then you can use it in any extending class without needing to override anything.
Figure out if $var should be passed in through a constructor rather than set after construction. If the object depends upon it, you should require it.
public function __construct($var) {
$this->var = $var;
}
That way you can't instantiate the object without setting the variable.
Enforce the instantiation of the class through the static method. If you're doing anything in there that you need to do, then make the constructor either protected or private. That way, someone can't bypass the static method.
protected function __construct() {}
private function __construct() {}
Edit: Based on your comment above, it sounds to me like you're trying to implement the Singleton Design Pattern. There's tons of information out there about why it's not a great idea and the bad things it may do. It has uses as well.
But there are a few other patterns that may be of use to you depending on what you're doing exactly.
You can use the Factory Method if you're trying to create different objects using the same steps.
If all of the objects start off the same and then are customized, you could use the Prototype Pattern.
You could use an Object Pool if it's particularly expensive to create your object.
But one thing to consider, is that in PHP objects are pretty light weight. Don't try to avoid creating a new object just for that overhead. Avoid doing heavy things like database queries or filesystem accesses multiple times. But don't worry about calling new Foo() unless foo's constructor is particularly heavy...
This looks like a simple factory method pattern.
You have a nice advantage: suppose that in the future you want to start using a different implementation (but that does the same thing). Using a factory you can change all the objects that are created in many places of a complex system simply by changing the creator method. Note that this would work easier if you used an external class (as is in the first link below).
Keeping it as you have now, you can also subclass this class and override the method to create a more complex object. I don't think this is what you want to achieve in here.
Anyway, this is good to enable Test Driven Development, abstraction and lots of other good things.
links:
Php patterns
Factory method pattern on wikipedia
If you're just creating an object, this isn't very usefull. You could just call a constructor. But if you're doing something more complicated (like you're starting with some sort of singleton pattern but haven't included all the details in this example), then:
This sounds about right. If you want to prevent objects created in the default way like this:
$obj = new Foo("Some Variable");
You can add a private constructor:
class Foo{
public $val;
private __construct(){}
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Now you enforce people to use your static class. The need to set the val in the function might be gone, so you could even add the value-parameter to your private constructor but do the other things (that you presumably want to do, like check for some sort of singleton pattern) in your 'bar' function
Super late but found this useful.
A good example of this in the wild is this static method from Audi's UI library returning an Array of instantiated TextField classes from within TextField's static method upgradeElements.
/**
* Class constructor for Textfield AUI component.
* Implements AUI component design pattern defined at:
* https://github.com/...
*
* #param {HTMLElement} element The element that will be upgraded.
*/
export default class Textfield extends Component {
/**
* Upgrades all Textfield AUI components.
* #returns {Array} Returns an array of all newly upgraded components.
*/
static upgradeElements() {
let components = [];
Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => {
if (!Component.isElementUpgraded(element)) {
components.push(new Textfield(element));
}
});
return components;
};
constructor(element) {
super(element);
}
...
See the rest in the repo
https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25
i'm php coder, trying to get into python world, and it's very hard for me.
Biggest enjoy of static methods in php is automatic builder of instance. No need to declare object, if you needed it once, in every file (or with different constructor params , in one line)
<?php
class Foo {
function __constructor__(){
$this->var = 'blah';
}
public static function aStaticMethod() {
return $this->var;
}
}
echo Foo::aStaticMethod();
?>
we can call constructor from static method don't we? and we can access everything in class as it would be simple method ... we can even have STATIC CONSTRUCTOR in php class and call it like so: Object::construct()->myMethod(); (to pass different params every time)
but not in python???? #staticmethod makes method in class a simple function that doesn't see totally anything ??
class socket(object):
def __init__(self):
self.oclass = otherclass()
print 'test' # does this constructor called at all when calling static method??
#staticmethod
def ping():
return self.oclass.send('PING') # i can't access anything!!!
print Anidb.ping()
I can't access anything from that god damned static method, it's like a standalone function or something like this..??
Maybe I'm using the wrong decorator? Maybe there's something like php offers with static methods in python?
1) Please tell why static methods is isolated
2) Please tell me how to make the same behavior like php static methods have.
3) Please tell me alternative practical use of this, if php static methods behavior is a bad thing
P.s. the goal of all this to write totally less code as much as possible.
P.p.s Heavy commenting of sample code is appreciated
Thank you.
static methods in PHP are not as you believe, they can't access to instance members. No $this! with them.
<?php
class Foo {
public static $var = 'foo ';
function __construct(){
echo 'constructing ';
$this->var = 'blah ';
}
public function aMethod() {
return $this->var;
}
public static function aStaticMethod() {
#return $this->$var; -> you can't do that,
# $this can be accessed only in instance methods, not static
return self::$var;
}
}
$foo = new Foo();
echo $foo->aMethod();
echo Foo::aStaticMethod();
?>
Python has three kind of methods in objects static methods are like functions defined ouside classes, the only use to put them in object is to keep them with the class as helper functions. class methods can access only to variables defined in the class (decorator #classmethod). This is more or less what PHP calls static members or methods. The first parameter of such methods sould be cls, and content of class can be accessed through cls. Normal methods must get self as first parameter and are the only ones to be able to access to instance members.
If you want several objects of the same type you definitely need instances, and the other types are not what you are looking for. If you only have one instance of an object, you could use class methods instead (or PHP static methods).
But in most case you should not bother doing that if you don't know why and just stick with instances of objects and normal methods, doing otherwise is premature optimization and your code is likely to bite you later because of the many restrictions you introduce.
You want classmethod instead. That provides the class as the first argument.
EDIT:
class C(object):
foo = 42
#classmethod
def printfoo(cls):
print cls.foo
C.printfoo()
I see you've already accepted another answer, but I'm not sure that it will work with your code. Specifically, the oclass variable is only created for instances of the class, not for the class itself. You could do it like this:
class socket(object):
oclass = otherclass()
#classmethod
def ping(cls):
return cls.oclass.send('PING')
socket.ping()
However, using your existing code and removing all decorators, you could simply instantiate it and use a method on the same line:
socket().ping()
I have a very special case in which I need to call a protected method from outside a class. I am very conscious about what I do programmingwise, but I would not be entirely opposed to doing so in this one special case I have. In all other cases, I need to continue disallowing access to the internal method, and so I would like to keep the method protected.
What are some elegant ways to access a protected method outside of a class? So far, I've found this.
I suppose it may be possible create some kind of double-agent instance of the target class that would sneakily provide access to the internals...
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 would think that in this case, refactoring so you don't require this sort of thing is probably the most elegant way to go. In saying that one option is to use __call and within that parse debug_backtrace to see which class called the method. Then check a friends whitelst
class ProtectedClass {
// Friend list
private $friends = array('secret' => array('FriendClass'));
protected function secret($arg1, $arg2) {
// ...
}
public function __call($method, $args) {
$trace = debug_backtrace();
$class = $trace[1]['class'];
if(in_array($class, $this->friends[$method]))
return $this->$method($args[0], $args[1]);
throw new Exception();
}
}
I think I need a shower.
This is a little kludgy, but might be an option.
Add a child class for the sake of accessing your protected function
public class Child extends Parent {
public function protectedFunc() {
return parent::protectedFunc();
}
}
Then, instantiate an instance of Child instead of Parent where you need to call that function.
I'm just throwing this out there since I haven't programmed in PHP in two years. Could you just add a function to the class that calls the protected method like so?
$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);');
Edit:
I think Tom's correct in looking at the documentation for create_function. It looks like the scope of $this will be "wrong" when you try to call it with this example.
It looks like traditional anonymous functions are supported since PHP 5.3.0 as well (and my first solution probably won't work), so I'd probably write it like this instead:
$obj->publicFunc = function($arg) {
return $this->protectedFunc($arg);
};
Since I think it looks a little cleaner (and your IDE of choice will highlight it better of course).
Ugh, I tried using Reflection to call the method but PHP won't allow you to do that either. It seems that you're going to have to use some sort of child class like the other posters have suggested. If you find a method that works, the developers will likely classify it as a bug in the future and break your code when you upgrade to the next version.
I recommend extending the class.
I'd think about what is the matter with the program design if I have to call a private function?
It used to be the case when
your class is responsible for several things (it is really two or thre calsses wrapped together) or
the rules of encapsulation are broken (utility functions, for example)
By finding any way to walk around this questions, you'll be nowhere nearer to the real solution.
Suppose your method declaration goes like so:
protected function getTheFoo() {
...
}
protected function setTheFoo($val) {
...
}
Usage:
$obj->__get('the_foo');
$obj->__set('the_foo', 'myBar');
This bypasses the protected methods and goes directly straight to the instance variables.