I'm working with a script that is calling the same class twice and throwing the error:
Fatal: Cannot redeclare class urlConverter (/var/www/core/cache/includes/elements/modsnippet/23.include.cache.php:14)
I have tried placing the following code in:
if( !class_exists( 'urlConverter', false ) )
{
$urlConverter = new urlConverter( $modx );
}
However doing that the CMS I'm working with is reporting an Error 500 and haven't been able to see in the logs why it's throwing that error.
Does anyone know how to check if that class has already been declared correctly?
Edit:
I'm using a CMS so as a result the Class is housed in a Snippet and not an actual file. This is how they call their snippets:
$data['viewonlinelink'] = $this->modx->runSnippet( 'urlConverter', array(
'action' => 'encrypt',
'string' => http_build_query( $string ) ) );
I need to call that a second time to get a different result.
Edit2:
Here is urlConverter:
<?php
class urlConverter {
public $modx;
public function __construct( modX &$modx )
{
$this->modx =& $modx;
}
public function action( $scriptProperties )
{
return $this->$scriptProperties['action']( $scriptProperties['string'] );
}
private function encrypt( $str )
{
return $str;
}
private function decrypt( $str )
{
return $str;
}
}
}
$urlConverter = new urlConverter( $modx );
return $urlConverter->action( $scriptProperties );
Now from another script I call the following:
$data['viewonlinelink'] = $this->modx->runSnippet( 'urlConverter', array(
'action' => 'encrypt',
'string' => http_build_query( $string ) ) );
$data['confirmonline'] = $this->modx->runSnippet( 'urlConverter', array(
'action' => 'encrypt',
'string' => http_build_query( $reversed ) ) );
Which runs the function encrypt inside of my urlConverter class and I should receive two different results.
In using your updated code, change the class file to this:
<?php
if(!class_exists('urlConverter')){
class urlConverter {
public $modx;
public function __construct( modX &$modx ){
$this->modx =& $modx;
}
public function action( $scriptProperties ){
return $this->$scriptProperties['action']( $scriptProperties['string'] );
}
private function encrypt( $str ){
return $str;
}
private function decrypt( $str ){
return $str;
}
}
}
$urlConverter = new urlConverter( $modx );
return $urlConverter->action( $scriptProperties );
The redeclare class error is not caused by creating a new instance of the class, it's called by invoking the class operator on the same symbol. You're probably including the urlConverter class definition file multiple times.
If you cannot modify the way your class file is brought into the CMS (by using require_once or include_once), modify your snippet:
if( !class_exists( 'urlConverter' ) ) {
class urlConverter {
/* Build class */
}
}
Of course if you have anything else in that same file, you'll want to make sure it doesn't try to run twice.
It looks like the file that defines the class is being included more than once which is why you are getting the first error (cannot redeclare class).
/var/www/core/cache/includes/elements/modsnippet/23.include.cache.php line 14 seems to be what is including the class multiple times. If possible, change the include to include_once so you don't define the class multiple times.
To debug further (instead of seeing the 500 internal server error), try adding the following to your code as early as possible:
error_reporting(E_ALL);
ini_set('display_errors', 1);
Otherwise, check the servers error_log (Apache) and see if there is any useful information there about the 500 error.
Related
I created a class. The code is below
class Another {
public $error = array();
public function set_error( $key, $value )
{
if ( isset( $key ) ) {
$sanitizedKey = sanitize_key( $key );
$this->error[ $sanitizedKey ] = wp_json_encode( $value );
return $this->error;
}
}
public function get_error( $id )
{
if ( ! is_null( $id ) ) {
return $this->error[ $id ];
}
}
public function print_error()
{
if ( $this->error ) {
foreach ($this->error as $key => $value) {
$decodeJson = json_decode( $value );
?>
<div class="ud-error">
<p class="ud-error-<?php echo $key; ?>">
<?php echo __( $decodeJson, 'ud-for-edd' ); ?>
</p>
</div>
<?php
}
}
}
}
If I invoke it in the following way it works. It echos the content as expected.
$error = new Another();
$error->set_error('gg', 'hhhh');
$error->print_error();
But if I use it with function then it doesn't work as expected. Do I have to pass parameters by reference or any other? The following way it doesn't work
function create_error($id, $val) {
$errr = new Another();
return $errr->set_error($id, $val);
}
create_error('raa', 'raashid');
$error = new Another();
$error->print_error();
I am confused about why this doesn't work. Any clue. Thanks in advance.
Steps I want the code to perform:
Create a class with 3 methods, set_error, get_error, and print_error
Then invoke the class inside the function. The function will accept two parameters because inside the class the set_error() method accepts two parameters.
In order to print the error, I will instantiate the class and call the print_error() method.
In case, if I have to print the new error. I will just call the create_error() function to do this for me. Because the function needs 2 parameters. The arguments supplied to the function must be supplied as arguments to the set_error() method.
I hope the list helps.
Update:
If I use a global variable then it works. Below is working.
$customError = new Another();
function create_error($id, $val) {
global $customError;
$customError->set_error($id, $val);
}
create_error('raa', 'rashid');
$customError->print_error();
Thanks, #roggsFolly and #El_Vanja. By understanding your tips I was able to solve the error. If there is anything wrong with the code I just said worked. Please point out.
The object you instantiate inside the function is not the same one you try and print the error message from.
First the object you instantiate inside the function scope is not visible outside the function.
function create_error($id, $val) {
$errr = new Another();
return $errr->set_error($id, $val);
}
create_error('raa', 'raashid');
// this instantiates a seperate Another object from the one
// you created in the function
$error = new Another();
// this tries to print from the new object taht has no message stored in it yet
$error->print_error();
To instantiate the object inside a function scope and then use that object outside the function scope you must pass that object back to the caller of the function
function create_error($id, $val) {
$errr = new Another();
$errr->set_error($id, $val);
return $errr; // this returns the object
}
$error = create_error('raa', 'raashid');
// now you can use its methods to print the stored message
$error->print_error();
Update as per your additional Information
A couple of things I think you may be getting confused about.
Each time you do $var = new ObjectName; you are creating a brand new instance of that class. This new instance has no knowledge about any other instances of that class that may or may not have been created before or may be created after that point. And more specifically to your problems, it does not have access to the properties of another version of that object.
You are I believe missing the concept of variable scope. The Object you create inside that function, will only actually exist while the function is running. Once the function completes anything created/instantiated wholly within that function is DESTROYED ( well in truth it is just no longer accessible ) but to all intent and purpose it is destroyed. you therefore cannot expect to be able to address it outside the scope of the function.
If you want the Object you instantiate within the function to be usable outside the function, you must pass a reference to that object out of the function to the calling code. This passes that reference into the scope of the calling code and keeps the object alive, global scope in your case, but that might be another function or even another object. That allows you access to that instantiation and any properties that were set within it.
I'm running Mediawiki 1.23 and using the Syntaxhighlight plugin. 90% of the time, we use SQL as the specified language. E.g.,:
<syntaxhighlight lang="sql">
select 'foo';
</syntaxhighlight>
So I thought, "Why not just have a separate "sql" tag that invokes highlighter and sets the language to SQL? I.e.,:
<sql>
select 'foo';
</sql>
So I tried the following, but it doesn't work. I'm probably misusing PHP and I could use some help.
In LocalSettings.php:
require_once "$IP/extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php";
In SyntaxHighlight_SeSHi.php I added the third setHook:
function efSyntaxHighlight_GeSHiSetup( &$parser ) {
$parser->setHook( 'source', array( 'SyntaxHighlight_GeSHi', 'parserHook' ) );
$parser->setHook( 'syntaxhighlight', array( 'SyntaxHighlight_GeSHi', 'parserHook' ) );
$parser->setHook( 'sql', array( 'SyntaxHighlight_GeSHi', 'parserHookSql' ) );
return true;
}
And finally in SyntaxHighlight_SeSHi.class.php I try to keep all the values that were coming in from the parser, but adding (or replacing) the "lang" value, and then call the original parserHook:
class SyntaxHighlight_GeSHi {
private static $initialised = false;
private static $languages = null;
public static function parserHookSql( $text, $args = array(), $parser ) {
$args['lang']='sql';
self::parserHook($text,$args,$parser);
}
public static function parserHook( $text, $args = array(), $parser ) {
global $wgSyntaxHighlightDefaultLang, $wgUseSiteCss, $wgUseTidy;
wfProfileIn( __METHOD__ );
self::initialise();
...
...
When I do this, the page renders but the rendered text from the sql tag is "UNIQ088c1443c530026e-sql-00000007-QINU", so I'm obviously doing something wrong.
So any help with my PHP, or maybe I'm extending mediawiki the wrong way... In either case, thanks in advance!
return self::parserHook($text,$args,$parser);
I want to create a smarter way to create if statements. I'm writing a function to do this:
if ( ! function_exists( 'get_meta' ) ) {
function get_meta($i) {
$fname_name = array(
'copyright_text',
'about_name',
'archive_name',
'contact_name',
'lenguage_name',
'cc_name',
'about_link',
'archive_link',
'contact_link',
'lenguage_link',
'cc_link',
'about_editors_name',
'about_responsibility_name',
'about_joinus_name',
'about_editors_link',
'about_responsibility_link',
'about_joinus_link'
);
foreach( $fname_name as $fname )
include_once( get_option($fname));
if ( $i ) return $fname_name[$i];
}
}
But when this function is called, it returns this error:
Warning: include_once() [function.include]: Failed opening 'what' for inclusion (include_path='.;php\PEAR') in local\wp-content\themes\net\0.6\functions.php on line 398
Basically, just want to add get_option(''); to each array, to return for example:
get_option('copyright_text');
or even more specific, to return:
get_option('copyright_text', '');
FIXED:
Okay, I just fix this by myself, but I'm so grateful of any advice here.
Instead using foreach and include_once, I use an even more simple solution:
if ($i) return get_option($fname_name[$i], '');
else if ($i == 0) return get_option($fname_name[0], '');
use this
foreach( $fname_name as $fname ){
include_once( get_option($fname));
if ( $i ) return $fname;
}
This looks like you are creating a shortcut for writing accessor methods. You would do yourself some good to take a look at PHP's magic methods. Specifically pay attention to __get, __set, and __call.
http://php.net/manual/en/language.oop5.magic.php
In this case, what you are doing looks similiar to the following:
class myClass {
// This could be associated with whatever other data you are interested in
private $_meta = array(
'copyright_text',
'about_name',
'archive_name',
'contact_name',
'lenguage_name',
'cc_name',
'about_link',
'archive_link',
'contact_link',
'lenguage_link',
'cc_link',
'about_editors_name',
'about_responsibility_name',
'about_joinus_name',
'about_editors_link',
'about_responsibility_link',
'about_joinus_link'
);
public function __get($name) {
if (in_array($name, $this->_meta)) {
return $this->_meta[$name];
}
}
}
I share the PHP code base across all pages and for each HTTP request I dynamically require the "/configs/$site/config.php" file. The file looks like this:
<?php
$SiteConfiguration = [
'site_title => 'Wiki for Developers',
'mysql_host' => 'localhost',
'mysql_db' => 'wiki-devs',
'articles_per_page' => 10,
/* ... etc ... */
];
?>
The problem I'm facing is that I can't quite access this variable from functions.
For example:
function DisplayArticles() {
echo "Displaying ".$SiteConfiguration['articles_per_page'];
}
It will print just Displaying and not Displaying 10.
How can I fix this and have my $SiteConfiguration accessible everywhere? Should I use a class? What's the best practice here?
put
global $SiteConfiguration;
in your function, you can find some more info at http://www.php.net/manual/en/language.variables.scope.php
Since you asked for best practice info: (simplest form)
class MySite{
public static function getConfig(){
return array(
'site_title => 'Wiki for Developers',
'mysql_host' => 'localhost',
'mysql_db' => 'wiki-devs',
'articles_per_page' => 10,
/* ... etc ... */
);
}
}
then in your code you can recall it with
$config = MySite::getConfig();
and use it. (obviously with a better, more descriptive name than MySite ;) )
Advantages:
your php class autoloader will automagically load it for you if setup correctly and your classes can be found, this means not worrying wether you passed a variable, not worrying about function argument placement and not tainting your functions with unnecessary arguments that don't help describe what it does.
you control exactly the access to this data and can make it so that not even your own functions can accidentally change this data, not even when calling other functions that would also need access to it.
in my opinion it beats globals and it beats passing via arguments since it's cleaner and you control the access to it in all forms. You can make certain attributes readonly/writable via specific getter/setter options, keep count of how many times it's accessed and whatever else you can think of.
Here's another case where a class for configuration would work great:
class Config {
private static $site_config = array( 'h' => 'Hello', 'w' => 'World');
public static function get( $key) {
return isset( self::$site_config[$key]) ? self::$site_config[$key] : null;
}
}
echo Config::get( 'h') . ' ' . Config::get( 'w');
This will output: Hello World
use global keyword
function DisplayArticles() {
global $SiteConfiguration;
echo "Displaying ".$SiteConfiguration['articles_per_page'];
}
Edit
You should try to avoid global variable.
A better practice would be to pass your array in parameter
function DisplayArticles( array $config ) {
echo "Displaying ".$config['articles_per_page'];
}
$SiteConfiguration = array( 'site_title' => 'Wiki for Developers',
'mysql_host' => 'localhost',
'mysql_db' => 'wiki-devs',
'articles_per_page' => 10,
/* ... etc ... */
);
DisplayArticles( $SiteConfiguration );
You can try something like this.
Your "siteConfiguration.php" file:
<?php
$SiteConfiguration = [
'site_title' => 'Wiki for Developers',
'mysql_host' => 'localhost',
'mysql_db' => 'wiki-devs',
'articles_per_page' => 10
];
return $SiteConfiguration;
?>
And this function:
function getConfigVar($var) {
static $config = array();
if( empty($config) ) {
$config = require("siteConfiguration.php");
}
return array_key_exists($var, $config) ? $config[$var] : null;
}
This function can also be modified to handle several configs.
How can i check to see if a static class has been declared?
ex
Given the class
class bob {
function yippie() {
echo "skippie";
}
}
later in code how do i check:
if(is_a_valid_static_object(bob)) {
bob::yippie();
}
so i don't get:
Fatal error: Class 'bob' not found in file.php on line 3
You can also check for existence of a specific method, even without instantiating the class
echo method_exists( bob, 'yippie' ) ? 'yes' : 'no';
If you want to go one step further and verify that "yippie" is actually static, use the Reflection API (PHP5 only)
try {
$method = new ReflectionMethod( 'bob::yippie' );
if ( $method->isStatic() )
{
// verified that bob::yippie is defined AND static, proceed
}
}
catch ( ReflectionException $e )
{
// method does not exist
echo $e->getMessage();
}
or, you could combine the two approaches
if ( method_exists( bob, 'yippie' ) )
{
$method = new ReflectionMethod( 'bob::yippie' );
if ( $method->isStatic() )
{
// verified that bob::yippie is defined AND static, proceed
}
}
bool class_exists( string $class_name [, bool $autoload ])
This function checks whether or not the given class has been defined.