In my class Helper() I have 2 methods which look like this:
public function is_active_page($page) {
$url = explode("/",$_SERVER["REQUEST_URI"]);
if (end($url) === $page) {
return true;
}
}
public function go_to_dashboard() {
if (isset($_SESSION['login'])) {
header('Location: http://example.com');
}
}
I would now like to call them like this: $helper->is_active_page('page')->go_to_dashboard(); instead of using 2 lines for each method.
For some reason this is not working for me. Why?
In order to be able to chain methods, those methods need to return the original Helper instance. Try returning $this from inside the methods. Like RomanPerekhrest commented however, I dont think the methods you listed here are suitable for chaining. You would be better off with adding another method to your class that combines the two you stated here.
I'm not exactly sure what you are trying to do, but something along the lines of below might be what you are looking for:
public function redirect($page){
if($this->is_active_page($page)){
$this->go_to_dashboard();
}
}
Lastly, you could think about reducing the scope of your is_active_page and go_to_dashboard functions, if they no longer need to be called from outside the Helper class.
Related
So I am making a Magento module in PHP. I want my logging to be consistent across all classes. My idea was to define a method in the helper class and call it. However being the pre-optimizer that I am, I figure making multiple calls to a class via the Mage::Helper() method to be more expensive than it needs to be, especially since most of my logging in singleton models anyways. So my now my idea is to use closures, define my method in the helper, make one call to the helper and register the method in a class variable.
class Comp_Mod_Helper_Data extends Mage_Core_Helper_Abstract {
public function getLogger() {
return function ($obj, $type= Zend_Log::DEBUG) {
Mage::log($obj, $logType, 'comp-mod.log', true);
};
}
}
Use:
class Comp_Mod__IndexController extends age_Core_Controller_Front_Action {
private $_log;
protected function _construct() {
$this->_log = Mage::Helper('mod')->getLogger();
}
}
However while it works ... it is not great to use. I'm either stuck doing:
$log = $this->_log;
$log('hello world');
// one awkward liner
($this->_log)('hello world');
While neat that it works is not readable nor standard, i.e. confusing!. The error that it get when using $this->_log('hello world'); is that the method does not exist. I assume because PHP is looking for a method call when using the syntax $this->method();
I do understand that A) I could just suck it up and use Mage::Helper everywhere, and B) that I could store the helper object in a variable and call like $this->helper->log(), and C) that static variables work, see PHP closure as static class variable
So, is there a way to get a non-static class variable to call the closure instead of looking for a non-existing method?
You could make use of the __call magic method:
class Comp_Mod__IndexController extends age_Core_Controller_Front_Action {
public function __call($method, array $args)
{
switch ($method)
{
case '_log':
return call_user_func_array(Mage::Helper('mod')->getLogger(), $args);
}
return null;
}
}
Then use it like you wanted to:
$this->_log('string to log');
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 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 am a beginner in php. and trying to work with Oauth. but this is not the point. the point is following: I have an Oauth class, there are four functions which return urls like this:
class tOauth{
......
function accessTokenURL() {
return 'http://api.twitter.com/oauth/access_token';
}
function authenticateURL() {
return 'http://api.twitter.com/oauth/authenticate';
}
......
}
this works fine. but now I want these functions to be generic, such that they are suitable for any social sites. this means I have to danymically pass all urls and return them at run time. so I come up something like this:
class tOauth{
....
public $accessTokenURL,$authenticateURL;
function accessTokenURL() {
return $this->accessTokenURL;
}
function authenticateURL() {
return $this->authenticateURL;
}
....
}
and at run time I call them like this:
$oauth=new Oauth(key,secret);
$oauth->accessTokenURL='http://www.facebook.com/oauth/access_token';
$oauth->authenticateURL='http://www.facebook.com/oauth/authenticate';
$token=$oauth->requestToken($someurl);
but for some reason, this doesn't seems to work. I did not change anything else. it seems I can not daynamically assign variables like this. does any body know what may be the problem? thanks for any tips.
Update: whole sample code can be find here: https://github.com/abraham/twitteroauth/blob/master/twitteroauth/twitteroauth.php
Why not write getter and setter methods for your class variables?
You already have methods, that return accessTokenURL and authentificateURL.
I believe this might work:
class tOauth{
....
public $accessTokenURL,$authenticateURL;
function accessTokenURL() {
return $this->accessTokenURL;
}
function authenticateURL() {
return $this->authenticateURL;
}
function set_accessTokenURL($token)
{
$this->accessTokenURL = $token;
}
function set_authenticateTokenURL($token)
{
$this->authenticateTokenURL = $token;
}
....
}
Update: Your code does not show any details about requestToken() method. The following solution gets you access token instead.
You read something you did not set according to your code. Replace the last line with
$token=$oauth->accessToken($someurl);
and it will work for accessToken.
Also consider inheritance that will allow you to store common instructions in tOauth class and the service-specific ones in separate classes inheriting from it (eg. Twitter_Oauth may inherit from your tOauth class and have specific URLs set to default from the beginning, without the need to set them every time).
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.