Okay So I know this is super basic and I should know how to do this but I'm blanking and having trouble finding the answer in Google. I have an include that has an array of variables for example
$phrases["text"][1] = "How much wood would a woodchuck chuck if a woodchuck could chuck wood?";
$phrases["mp3"][1] = "http://example.com/file.mp3";
Then a function that gets the varibles:
function return_phrase($phrase_name="", $fallback="",$default ="text"){
$next= (isset($default) && $default =="mp3") ? 'text' : 'mp3';
if(isset($tts_phrases[$default][$phrase_name])){
return $phrases[$default][$phrase_name]);
}
else if(isset($tts_phrases[$next][$phrase_name])){
return $phrases[$next][$phrase_name]);
}
else{
return $fallback;
}
}
The problem is that the $phrases arrays aren't being sent to the function I can include the file in the function itself but I know that's the wrong way to do it. I think I need to use $global just not sure how.
Method 1: Pass $phrases, $tts_phrases as parameters
function return_phrase(array $phrases, array $ttphrases, $phrase_name="", $fallback="",$default ="text"){
$next= (isset($default) && $default =="mp3") ? 'text' : 'mp3';
if(isset($tts_phrases[$default][$phrase_name])){
return $phrases[$default][$phrase_name]);
}
else if(isset($tts_phrases[$next][$phrase_name])){
return $phrases[$next][$phrase_name]);
}
else{
return $fallback;
}
}
Method 2: Make $phrases, $tts_phrases global (bad!)
function return_phrase($phrase_name="", $fallback="",$default ="text"){
global $phrases, $tts_phrases;
$next= (isset($default) && $default =="mp3") ? 'text' : 'mp3';
if(isset($tts_phrases[$default][$phrase_name])){
return $phrases[$default][$phrase_name]);
}
else if(isset($tts_phrases[$next][$phrase_name])){
return $phrases[$next][$phrase_name]);
}
else{
return $fallback;
}
}
Using global variables is a quick and easy fix, but once your application gets larger they become very hard to keep track of. For example, take this legacy code snippet that I have to deal with at work:
function foo() {
global $mysqldsn, $ldapdsn, $autologout_timer, $isMobileDevice, logout_fail_limit, $logout_fail_window, $lang, $project_contact_email, $project_contact_name ... (50 or 60 more global variables following)
...
}
Any time I am looking at one of the pages that just pulls one of those variables out of thin air, I have to Ctrl+F the whole project and make sure that every little change hasn't messed up the whole app. When you keep your variables in local scope, you know exactly what you are changing.
Related
Until yesterday I was burning my brain trying to switch from a procedural thinking to a OOP thinking; this morning I gave up. I said to my self I wasn't probably ready yet to understand it.
I started then coding in the usual way, writing a function to check if there's the cookie "logged" or not
function chkCookieLogin() {
if(isset($_COOKIE["logged"])) {
$logged = 'true';
$cookieValue = $_COOKIE["logged"];
return $logged;
return $cookieValue;
}
else {
$logged = 'false';
return $logged;
}
}
$result = chkCookieLogin();
if($result == 'true'){
echo $cookieValue;
}
else {
echo 'NO COOKIE';
}
since I run across a problem: I wanted to return two variables ($logged and $cookieValue) instead of just one. I google it and I found this answer where Jasper explains a method using an OOP point of view (or this is what I can see).
That answer opened me a new vision on the OOP so I tried to rewrite what I was trying to achieve this way:
class chkCookie {
public $logged;
public $cookieValue;
public function __construct($logged, $cookieValue) {
$this->logged = $logged;
$this->cookieValue = $cookieValue;
}
function chkCookieLogin() {
$out = new chkCookie();
if(isset($_COOKIE["logged"])) {
$out->logged = 'true';
$out->cookieValue = $_COOKIE["logged"];
return $out;
}
else {
$out->logged = 'false';
return $out;
}
}
}
$vars = chkCookieLogin();
$logged = $vars->logged;
$cookieValue = $vars->cookieValue;
echo $logged; echo $cookieValue;
Obviously it didn't work at the first attempt...and neither at the second and the third. But for the first time I feel I'm at one step to "really touch" the OOP (or this is what I think!).
My questions are:
is this attempt correctly written from the OOP point of view?
If yes, what are the problems? ('cause I guess there's more than one)
Thank you so much!
Credit to #NiettheDarkAbsol for the idea of returning an Array data-type.
Using dependency injection, you can set-up an object like this:
class Factory {
private $Data = [];
public function set($index, $data) {
$this->Data[$index] = $data;
}
public function get($index) {
return $this->Data[$index];
}
}
Then to use the DI module, you can set methods like so (using anonymous functions):
$f = new Factory();
$f->set('Cookies', $_SESSION);
$f->set('Check-Cookie', function() use ($f) {
return $f->get('Cookies')['logged'] ? [true, $f->get('Cookies')['logged']] : [false, null];
});
Using error checks, we can then call the method when and as we need it:
$cookieArr = is_callable($f->get('Check-Cookie')) ? call_user_func($f->get('Check-Cookie')) : [];
echo $cookieArr[0] ? $cookieArr[1] : 'Logged is not set';
I'd also consider adding constants to your DI class, allowing more dynamic approaches rather than doing error checks each time. IE, on set() include a constant like Factory::FUNC_ARRAY so your get() method can return the closure already executed.
You can look into using ternary operators if you're confused.
See it working over at 3v4l.org.
If it means anything, here is an OOP styled approach.
I've been racking my brains over this one but I'll do my best to describe the problem as best as possible. I have a custom function written within template.php, with a bunch of conditionals. When a condition is true, I would like to assign a value to a variable, and then pass that variable intro a node preprocess function that allows that variables to be rendered on a node template.
The function containing the condition:
function _mytheme_date_repeat_string($vars) {
$exdate_pos = strpos($rrule['WKST'], 'EXDATE:');
if($exdate_pos > 0) {
$vars['testvar'] = 'abc123';
}
}
The preprocess function that I would like to render the variable in for node template use:
function mytheme_preprocess_node(&$vars, $hook) {
$vars['new_variable'] = $testvar;
}
Intended usage in node.tpl.php:
<?php print $new_variable; ?>
I'm not great with PHP, but I know enough about programming to know that variable scope might be an issue here. What would be the best way to implement this? Any guidance is greatly appreciated.
Thanks,
Mark.
If it is not called, your _mytheme_date_repeat_string() function will never be executed. Preprocess functions (ie. any function starting mytheme_preprocess_, are called automatically by Drupal's theme system.
What you need is either move the code of _mytheme_date_repeat_string() in mytheme_preprocess_node() or refactor it and call it.
function _mytheme_date_repeat_string($rrule) {
$exdate_pos = strpos($rrule['WKST'], 'EXDATE:');
if($exdate_pos > 0) {
return 'abc123';
}
else {
return NULL;
}
}
/**
* Prepares variables for node templates.
*/
function mytheme_preprocess_node(&$variables, $hook) {
// Get $rrule from somewhere
$rrule = ... ;
$testvar = _mytheme_date_repeat_string($rrule);
if ($testvar) {
$variables['new_variable'] = $testvar;
}
}
You code does not show where the $rrule calue comes from. I assume you would get it for $variables['node'].
I am front of reflexion about my php developments. I'm trying to optimize my code.
I have often condition like this :
if($userConnected->getType() == User::BUYER_ACCOUNT_TYPE || $userConnected->getType() == User::ADMIN_ACCOUNT_TYPE){//Mycode}
My question is : Is it possible to have something like this :
if($userConnected->getType() == User::BUYER_ACCOUNT_TYPE || User::ADMIN_ACCOUNT_TYPE)
Actually the best way I found to do this is :
if(in_array($userConnected->getType(), array(User::BUYER_ACCOUNT_TYPE, User::ADMIN_ACCOUNT_TYPE)))
And I want to know if there is a better way ?
Thank you in advance
Thomas
You can add some public methods to your User class to check if the user is a buyer or an admin:
public function isBuyer()
{
return $this->type === self::BUYER_ACCOUNT_TYPE;
}
public function isAdmin()
{
return $this->type === self::ADMIN_ACCOUNT_TYPE;
}
Having these methods you can simply check:
if ($userConnected->isBuyer() || $userConnected->isAdmin())
You can go further and do a single method if the condition above is used very often:
public function isAllowed() // just an example of a method name
{
return $this->isBuyer() || $this->isAdmin();
}
I have a function that takes an input variable and outputs a template with the following call:
outputhtml($blue_widget);
outputhtml($red_widget);
outputhtml($green_widget);
And a simplified version of the function:
function outputhtml($type)
{
static $current;
if (isset($current))
{
$current++;
}
else
{
$current = 0;
}
//some logic here to determine template to output
return $widget_template;
}
Now here is my problem. If I call the function in a script three times or more, I want the output to be one way, but if I only call the function twice, then I have some html changes that need to be reflected in the templates that are returned.
So how can I modify this function to determine if there are only two calls for it. I can't go back after the fact and ask "hey function did you only run twice???"
Having trouble getting my head around how I tell a function that it is not going to be used after the second time and the necessary html modifications can be used. How would I go about accomplishing this?
function outputhtml($type)
{
static $current = 0;
$current++;
//some logic here to determine template to output
if ($current === 2) {
// called twice
}
if ($current > 2) {
// called more than twice
}
return $widget_template;
}
That would not be practical using a static $current inside the function; I would suggest using an object to maintain the state instead, like so:
class Something
{
private $current = 0;
function outputhtml($type)
{
// ... whatever
++$this->current;
return $template;
}
function didRunTwice()
{
return $this->current == 2;
}
}
The didRunTwice() method is asking "did you run twice?".
$s = new Something;
$tpl = $s->outputhtml(1);
// some other code here
$tpl2 = $s->outputhtml(2);
// some other code here
if ($s->didRunTwice()) {
// do stuff with $tpl and $tpl2
}
The only way you can find out if a function was only called twice is by putting the test at the end of your code; but perhaps by then the templates are no longer accessible? Can't tell much without seeing more code.
Inherited an old CakePHP site and I'm trying to figure out what some functions do. I have several functions that have the same name as another function but with an underscore first, e.g. save() and _save(). However the function _save() is never called in any context, though save() is.
I read this question and it looks like it's from an old worst-practices exercise, but that doesn't really explain why it's in my code; you still have to call function _save() as _save() right? If there's no calls to _save() is it safe to remove?
I want it gone, even the save() function wasn't supposed to be there, rewriting perfectly good framework functionality. It looks like an older version of the same function, but there's no comments and I don't know if there's some weird context in which php/Cake will fall back to the underscored function name.
Here's the code for the curious. On closer inspection it appears the underscored functions were old versions of a function left in for some reason. At least one was a "private" method being called (from a public function of the same name, minus the underscore...):
function __save() {
$user = $this->redirectWithoutPermission('product.manage','/',true);
if ($this->data) {
$this->Prod->data = $this->data;
$saved_okay = false;
if ($this->Prod->validates()) {
if ($this->Prod->save()) $saved_okay = true;
}
if ($saved_okay) {
$product_id = ($this->data['Prod']['id']) ? $this->data['Prod']['id'] : $this->Prod->getLastInsertId();
if ($this->data['Plant']['id']) {
$this->data['Prod']['id'] = $product_id;
$this->Prod->data = $this->data;
$this->Prod->save_plants();
$this->redirect('/plant/products/'.$this->data['Plant']['id']);
} else {
$this->redirect('/product/view/'.$product_id);
}
die();
} else {
die('did not save properly');
}
} else {
die('whoops');
}
}
function save() {
$user = $this->redirectWithoutPermission('product.manage','/products',true);
if ($this->data) {
$this->Prod->data = $this->data;
if ($this->Prod->validates()) {
$this->Prod->save();
$gotoURL = isset($this->data['Navigation']['goto'])?$this->data['Navigation']['goto']:'/';
$gotoURL = str_replace('%%Prod.id%%', $this->data['Prod']['id'], $gotoURL);
if (isset($this->data['Navigation']['flash'])) {
$this->Session->setFlash($this->data['Navigation']['flash']);
}
if (isset($this->params['url']['ext']) && $this->params['url']['ext']=='ajax') {
$value = array(
'success'=>true
,'redirect'=>$gotoURL
);
print $this->Json->encode($value);
} else {
$this->redirect($gotoURL);
}
} else {
$value = array(
'success'=>false
,'message'=>"You have invalid fields."
,'reason'=>'invalid_fields'
,'fields'=>array(
'Prod'=>$this->Prod->invalidFields()
)
);
print $this->Json->encode($value);
}
} else {
$this->redirect('/products');
}
die();
}
I had hoped to learn whether or not some convention applied to this situation, but from testing I've found the functions are not called which is really the answer to the question I asked.