I'm using the Markdown library for PHP by Michel Fortin. Setup is easy and it works great like this:
include_once "markdown.php";
$my_html = Markdown($my_text);
However, I have a class in which I want to pass stuff and 'Markdown' it, like so:
class Test
{
public function showMarkdown ($text)
{
return Markdown($text);
}
}
Obviously, my class is much larger than this, but this is what it boils down to. In my main script I do:
include_once "markdown.php";
$test = new Test();
echo $test->showMarkdown($text);
This returns an error, saying the function 'Markdown' is undefined. That seems obvious, because it's not within the class and I haven't used a scope operator. But when I put the include inside my class and use $this->Markdown or self::Markdown the function is still undefined. I figured that the Markdown function can't be defined inside another function.
So, how can I solve this? I need to do the include, which loads the Markdown function (and the rest of its family) but I want to be able to use it from within my classes.
Thanks for your answers/ideas.
Your example code calls a free function called Markdown (which presumably is defined in markdown.php). You simply need to put the include in the same file as your Test class.
After doing this, you will still call Markdown as a free function, and not as an instance ($this->Markdown) or static (self::Markdown) method.
write
function showMarkdown ($text)
in place of
public function showMarkdown ($text)
and
echo $test->showMarkdown("Hello World");
Related
I have a class with property transof
class translator {
public function transof($phrase) { gives translation of phrase }
}
Now I want to pass an instance of translator to a function:
function parse($part,$class) {
$class->transof($part);
}
$tr = new translator("project","en");
parse("exception",$tr);
Do anyone know how to do this?
I know this example is to simple, and can be easily written without the use of a function, but in my real world example I would like to be able to use a function.
Of course I can use global $tr in the function, and use it inside the function, but I don't like using global.
Thanks in advance
If you do not want to create object in global code to have better maintainability then you need to modify the signature of the function as follows:
function parse($part,$project,$lang) {
$class = new Translator($project,$lang);
$class->transof($part);
}
parse("exception","project","en");
It does what you intend, the object is passed to the function parse. All you need to do is to include the class definition file in or before the php file which contains parse definition or get use of __autoload() function which will include class definition when needed.
You can also define parse this way:
function parse($part, translator $class) {
$class->transof($part);
}
Then code editors as Aptana etc. will know what class this object is an instance of and will be able to provide you with hints concerning your class structure.
Can functions be called without a class outside of a class?
I have some code that I found to do hashing and authentication for my passwords. The php file however doesn't have a class declaration at the top just the functions. I'm not sure how to call the functions from my other pages. Here is the hashing file I'm using
The Hashing file is set up like this :
<?php
public function MyFunction() {
}
Rather than like this:
<?php
class MyClass{
public function MyFunction() {
}
}
I have tried
include_once 'PasswordHash.php';
Then in my page calling the functions with these:
Echo PasswordHash::create_hash('$Pass');
Echo create_hash('$Pass');
Echo PasswordHash->create_hash('$Pass');
None of them work and show Fatal error:blah blah cant find class.
Thank you for reading and your help.
You will need to initiate your classes.
$password = new PasswordHash($pass);
echo $password->create_hash;
Or something along those lines.
Several issues:
create_hash('$pass') will create a hash of the string $pass, not the value of the variable, pass like this: create_hash($pass)
You must create an instance of your class, before you can call its methods.
You linked to a non-OO code example, why bother using classes, instead of using the code that is already there?
So, if you are going to continue using this class:
$hasher = new MyClass();//or whatever name you gave the class
echo 'The hash of the password is: ', $hasher->createHash($pass);//<-- change createHash with correct method name
If you are going to copy paste the example code (if it's allowed), simply call it like any old function:
echo 'The hash of the password is: ', create_hash($pass);
But make sure the functions are declared:
if (!function_exists('create_hash'))
include 'path/to/file/containing/create_hash_functions.php';
Oh, and functions outside a class don't have access modifiers:
function thisWorks(){}
//note: no public
public function thisFails(){}// <== error!
I found that you must create the object then you can work with it.
no need to make it a class just the functions.
include_once '../Resources/PasswordHash.php';
$result = validate_password("foobar", $hash);
That was all it needed.
Just to be included and then you can call it like any other function in the class.
I have got a PHP file in which there are some functions (not included in a class). I am using PHPUnit to testing. When I try to generate in a simply way a test file from a file containing functions, the log says:
Could not find class...
Is there any possibility to test functions which are not methods?
Yes, you can with something like this:
includes/functions.php
function my_function() {
return true;
}
tests/MyFunctionTest.php
require_once '../includes/functions.php';
class MyFunctionTest extends PHPUnit_Framework_TestCase
{
public function testReturnValue()
{
$return_value = my_function();
$this->assertTrue($return_value);
}
}
So as long as your function is within scope you can call it from your test method just like any other PHP function in any other PHP framework or project.
If I'm right then PhpUnit works only with classes hence methods. So just convert them into the methods for testing purpose. Shouldn't be hard.
Can you declare a function like this...
function ihatefooexamples(){
return "boo-foo!";
};
And then redeclare it somewhat like this...
if ($_GET['foolevel'] == 10){
function ihatefooexamples(){
return "really boo-foo";
};
};
Is it possible to overwrite a function that way?
Any way?
Edit
To address comments that this answer doesn't directly address the
original question. If you got here from a Google Search, start here
There is a function available called override_function that actually fits the bill. However, given that this function is part of The Advanced PHP Debugger extension, it's hard to make an argument that override_function() is intended for production use. Therefore, I would say "No", it is not possible to overwrite a function with the intent that the original questioner had in mind.
Original Answer
This is where you should take advantage of OOP, specifically polymorphism.
interface Fooable
{
public function ihatefooexamples();
}
class Foo implements Fooable
{
public function ihatefooexamples()
{
return "boo-foo!";
}
}
class FooBar implements Fooable
{
public function ihatefooexamples()
{
return "really boo-foo";
}
}
$foo = new Foo();
if (10 == $_GET['foolevel']) {
$foo = new FooBar();
}
echo $foo->ihatefooexamples();
Monkey patch in namespace php >= 5.3
A less evasive method than modifying the interpreter is the monkey patch.
Monkey patching is the art of replacing the actual implementation with a similar "patch" of your own.
Ninja skills
Before you can monkey patch like a PHP Ninja we first have to understand PHPs namespaces.
Since PHP 5.3 we got introduced to namespaces which you might at first glance denote to be equivalent to something like java packages perhaps, but it's not quite the same. Namespaces, in PHP, is a way to encapsulate scope by creating a hierarchy of focus, especially for functions and constants. As this topic, fallback to global functions, aims to explain.
If you don't provide a namespace when calling a function, PHP first looks in the current namespace then moves down the hierarchy until it finds the first function declared within that prefixed namespace and executes that. For our example if you are calling print_r(); from namespace My\Awesome\Namespace; What PHP does is to first look for a function called My\Awesome\Namespace\print_r(); then My\Awesome\print_r(); then My\print_r(); until it finds the PHP built in function in the global namespace \print_r();.
You will not be able to define a function print_r($object) {} in the global namespace because this will cause a name collision since a function with that name already exists.
Expect a fatal error to the likes of:
Fatal error: Cannot redeclare print_r()
But nothing stops you, however, from doing just that within the scope of a namespace.
Patching the monkey
Say you have a script using several print_r(); calls.
Example:
<?php
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
But you later change your mind and you want the output wrapped in <pre></pre> tags instead. Ever happened to you?
Before you go and change every call to print_r(); consider monkey patching instead.
Example:
<?php
namespace MyNamespace {
function print_r($object)
{
echo "<pre>", \print_r($object, true), "</pre>";
}
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
}
Your script will now be using MyNamespace\print_r(); instead of the global \print_r();
Works great for mocking unit tests.
nJoy!
Have a look at override_function to override the functions.
override_function — Overrides built-in
functions
Example:
override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
short answer is no, you can't overwrite a function once its in the PHP function scope.
your best of using anonymous functions like so
$ihatefooexamples = function()
{
return "boo-foo!";
}
//...
unset($ihatefooexamples);
$ihatefooexamples = function()
{
return "really boo-foo";
}
http://php.net/manual/en/functions.anonymous.php
You cannot redeclare any functions in PHP. You can, however, override them. Check out overriding functions as well as renaming functions in order to save the function you're overriding if you want.
So, keep in mind that when you override a function, you lose it. You may want to consider keeping it, but in a different name. Just saying.
Also, if these are functions in classes that you're wanting to override, you would just need to create a subclass and redeclare the function in your class without having to do rename_function and override_function.
Example:
rename_function('mysql_connect', 'original_mysql_connect' );
override_function('mysql_connect', '$a,$b', 'echo "DOING MY FUNCTION INSTEAD"; return $a * $b;');
I would include all functions of one case in an include file, and the others in another include.
For instance simple.inc would contain function boofoo() { simple } and really.inc would contain function boofoo() { really }
It helps the readability / maintenance of your program, having all functions of the same kind in the same inc.
Then at the top of your main module
if ($_GET['foolevel'] == 10) {
include "really.inc";
}
else {
include "simple.inc";
}
You could use the PECL extension
runkit_function_redefine — Replace a function definition with a new implementation
but that is bad practise in my opinion. You are using functions, but check out the Decorator design pattern. Can borrow the basic idea from it.
No this will be a problem.
PHP Variable Functions
Depending on situation where you need this, maybe you can use anonymous functions like this:
$greet = function($name)
{
echo('Hello ' . $name);
};
$greet('World');
...then you can set new function to the given variable any time
A solution for the related case where you have an include file A that you can edit and want to override some of its functions in an include file B (or the main file):
Main File:
<?php
$Override=true; // An argument used in A.php
include ("A.php");
include ("B.php");
F1();
?>
Include File A:
<?php
if (!#$Override) {
function F1 () {echo "This is F1() in A";}
}
?>
Include File B:
<?php
function F1 () {echo "This is F1() in B";}
?>
Browsing to the main file displays "This is F1() in B".
I have a php site which flows as shown below. Please note I'm leaving out most of the code (wherever theres an ellipses).
index.php
include template.php
...
$_template = new template;
$_template->load();
...
template.php
class pal_template {
...
public function load() {
...
include example.php;
...
}
example.php
...
global $_template;
$_tempalate->foo();
...
Now, this works fine. However, I end up having a ton of files that are displayed via the $_template->load() method, and within each of these files I'd like to be able to make use of other methods within the template class.
I can call global $_template in every file and then it all works fine, but if possible I'd really like for the object $_template to be available without having to remember to declare it as global.
Can this be done, and what is the best method for doing it?
My goal is to make these files that are loaded through the template class very simple and easy to use, as they may need to be tweaked by folks who basically know nothing about PHP and who would probably forget to put global $_template before trying to use any of the $_template methods. If $_template were already available in example.php my life would be a lot easier.
Thanks!
You can define globals before you include 'example.php'.
global $_template;
include 'example.php'
Or you could do this:
$_template = $this;
include 'example.php'
Or inside example.php:
$this->foo();
The use of global is strongly not recommended.
By the way, consider this :
-> index.php
$_template = new template;
$_template->load();
-> template.php
class template {
public function load() {
include 'example.php';
}
public function showMessage($file) {
echo "Message from '{$file}'";
}
}
-> example.php
<?php
$this->showMessage(__FILE__);
Will output something like
Message from '/path/to/example.php'
I recommend you to not use "global", as Yanick told you as well.
What you probably need is the Registry design pattern. Then you can add the template to the registry and give it to every object. In general I would recommend you to learn about design patterns. Here are some more you could learn.