I'm a complete beginner so sorry if the way I word this is confusing.
I'm working on my online computer science course right now and we're practising functions. What we're supposed to do is set three sentences to output three different variables inside the sentence
x is y years old and is z
Here's what I mean:
Obama is 50 years old and is president of the United States.
Bill Gates is 60 years old and is Founder of Microsoft.
Jacob is 20 years old and is a student.
This is the code that I currently have:
<?php
function displayStory($name) {
}
function displayAge($age) {
}
function displayJob($job) {
echo $name . " is " . $age . " and is " . $job . ".<br />";
}
displayStory("Obama");
displayAge("50");
displayJob("the President of The United States");
displayStory("Bill Gates");
displayAge("60");
displayJob("the founder of Microsoft");
displayStory("Jacob");
displayAge("20");
displayJob("a student");
?>
I'm sure there's an easier way to complete this and I know other ways to complete this, but we're supposed to use the function DisplayX to complete this.
Thank you in advance :)
What you are looking for is user-defined functions.
A function is basicly a set of instructions, these instructions are generalized with a name. To create one single function, you use the function keyword followed by a space and the name of the function.
In this case, this functionality you need could be achieved by just one function. You can name it something like displayInformation.
The function is gonna need 3 parameters, which are the 3 things you are wanting to display. The name, the age and the job of the person. Parameters should be defined in ( )'s as variables which comes after the function name.
To create this function, it looks something like this:
function displayInformation($name, $age, $job) {
}
The context of the function can now simply be the echo'ing of the data like you did in one of your functions.
echo $name . " is " . $age . " and is " . $job . ".<br />";
The final result of this code would be:
<?php
function displayInformation($name, $age, $job) {
echo $name . " is " . $age . " and is " . $job . ".<br />"
}
displayInformation("Obama", 50, "president of the United States");
displayInformation("Bill Gates", 60, "Founder of Microsoft");
displayInformation("Jacob", 20, "a student");
For more information on user-defined functions, you can read the documentation.
Function design
As for personal preference, best practices and this specific case, you can design your function in another way.
When using PHP functions, it is always going to return a value. This can be a number, some text, a object, you name it.
You could remove the functionality of the function to already "display" the personal information, and just make it return the personal information as a string. This could be done by the return keyword like this:
function getInformation($name, $age, $job) {
return $name . " is " . $age . " and is " . $job . ".<br />"
}
Now you only have to use echo to display the information.
echo getInformation("Obama", 50, "president of the United States");
echo getInformation("Bill Gates", 60, "Founder of Microsoft");
echo getInformation("Jacob", 20, "a student");
More information about returning values can be found here.
If you want to just use a function then you can simplify your function to the following:
function display($name, $age, $job) {
echo $name . " is " . $age . " and is " . $job . ".<br />"
}
display("Obama", 50, "president of the United States");
display("Bill Gates", 60, "Founder of Microsoft");
display("Jacob", 20, "a student");
This will echo out:
Obama is 50 years old and is president of the United States
Bill Gates is 60 years old and is Founder of Microsoft
Jacob is 20 years old and is a student
However you should look at creating classes which are easier to maintain in the long run.
class personInformation {
public $name;
public $age;
public $job;
public function __construct($name, $age, $job) {
$this->name = $name;
$this->age= $age;
$this->job= $job;
}
public function display() {
return $this->name . ' is ' . $this->age . ' and is ' . $this->job . '.<br />';
}
}
Then using this class you can do:
/* Start a new instance of the class */
$obama = new personInformation("Obama", 50, "president of the United States");
$bill = new personInformation("Bill Gates", 60, "Founder of Microsoft");
$jacob = new personInformation("Jacob", 20, "a student");
/* Display the sentences */
echo $obama->display();
echo $bill->display();
echo $jacob->display();
the __construct function is the same as setting each value seperately however it does it when you call a new instance of the class. So rather doing this:
$obama = new personInformation();
$obama->name = "obama";
$obama->age= 50;
$obama->job= "president of the United States";
You create the __construct function however note that you must fill in all the information in the __construct else it will error so you cannot do:
$obama = new personInformation("Obama", 50);
You can add further functions to the class for example:
public function hello() {
return $this->name . ' says hello. <br />';
}
If you don't recognise what's below, fair enough. But some topics to Google and read about are:
PHP variable scope
Object Orientated Programming
So my solution is that you generate a class which handles all the data for the chosen person in an object orientated fashion:
class sentence {
private $name;
private $age;
private $job;
//this is the sentence string that will be
//populated with your data, currently given a default value.
public $output = $this->name . " is " . $this->age . " and is " . $this->job . "!";
/***
Within the class you can create methods which is another
name for functions.
***/
public function setName($name){
$this->name = $name;
}
public function setAge($age){
$this->age = (int)$age; //forces to integer type.
}
public function setJob($job){
//you can fill this one in.
}
} //close class.
So that is the class, how do you use it, well you first create the class as so:
$one = new sentence();
And then add data to it using the functions we set above to save the data parts to the corresponding values.
$one->setAge("50");
$one->setName("george");
And then display the output as follows, note that calling a variable inside a class, rather than a method, means you do not use brackets. So:
//output
print $sentence->output;
This will output
George is 50 and is !
Classes are typcally built in PHP include files and not usually in the file they are usedin.
Related
I have this in my model called B:
public function getA() {
return $this->hasOne(\app\models\A::className(), ['id' => 'A_Id']);
}
public function getDispName() {
return $this->a->attr . ' ' . $this->attr . ' ' . $this->attr2;
}
works everything fine, until I go to Create. Then I get the following "error":
PHP Notice – yii\base\ErrorException Trying to get property of non-object
As a workaround I have done this:
public function getDispName() {
if (is_object($this->a)) {
return $this->a->attr . ' ' . $this->attr . ' ' . $this->attr2;
}
}
I'm not sure if this is a good solution, or why do I get this "notice" only at create, but I would like to understand and do it correctly. I don't want this to cause problems somewhere else. Maybe I miss something other basic and important knowledge. If you have any ideas, I would be grateful to hear it. Thanks.
You are probably trying to use a B model that does not have a A model attached. If that is the case of course your function would fail. Are you sure for every B you have an A? Probably you are inserting a B and not inserting an A and trying to show info on it.
Your options are:
1) do exactly like you did, maybe change it to
public function getDispName() {
$display = '';
if (is_object($this->a)) {
$display = $this->a->attr;
}
return $display . ' ' . $this->attr . ' ' . $this->attr2;
}
2) fix your code to always make sure you insert an A when you insert a B. It can be an empty record but it has to be a record.
This property is based on others properties, so when you create new object of type A you don't need to indicate this property. Indicate only fields from which it consists.
Open /views/model_name/_form.php and delete row with property dispName
<?= $form->field($model, 'dispName')->textInput() ?> // or textarea or ...
I am new to PHP. I now learn the visibility scope concept (also known as access modifiers).
I read the following two links also on this forum:
Failed to get an object property that containing ":protected"
What is the difference between public, private, and protected?
I created a simple class in a file named "class.Address.inc":
<?php
/**
* Physical address.
*/
class Address {
// Street address.
public $street_address_1;
public $street_address_2;
// Name of the City.
public $city_name;
// Name of the subdivison.
public $subdivision_name;
// Postal code.
public $postal_code;
// Name of the Country.
public $country_name;
// Primary key of an Address.
protected $_address_id;
// When the record was created and last updated.
protected $_time_created;
protected $_time_updated;
/**
* Display an address in HTML.
* #return string
*/
function display() {
$output = '';
// Street address.
$output .= $this->street_address_1;
if ($this->street_address_2) {
$output .= '<br/>' . $this->street_address_2;
}
// City, Subdivision Postal.
$output .= '<br/>';
$output .= $this->city_name . ', ' . $this->subdivision_name;
$output .= ' ' . $this->postal_code;
// Country.
$output .= '<br/>';
$output .= $this->country_name;
return $output;
}
}
Then, I created a simple program in the file demo.php as follows:
require 'class.Address.inc';
echo '<h2>Instantiating Address</h2>';
$address = new Address;
echo '<h2>Empty Address</h2>';
echo '<tt><pre>' . var_export($address, TRUE) . '</pre></tt>';
echo '<h2>Setting properties...</h2>';
$address->street_address_1 = '555 Fake Street';
$address->city_name = 'Townsville';
$address->subdivision_name = 'State';
$address->postal_code = '12345';
$address->country_name = 'United States of America';
echo '<tt><pre>' . var_export($address, TRUE) . '</pre></tt>';
echo '<h2>Displaying address...</h2>';
echo $address->display();
echo '<h2>Testing protected access.</h2>';
echo "Address ID: {$address->_address_id}";
Everything works in the above program except of the last line. I am getting a fatal error saying I can`t access the "_address_id property". Why?
Protected scope is when you want to make your variable/function visible in all classes that extend current class including the parent class.
"$address" object comes from the current class named Address. So what am I doing wrong?
Please assist.
Qwerty
The code that tries to access the protected property has to be in a method of the class or a class that extends it. The echo line that you're asking about is not in any class method, it's in the global code of the script. Protected and private properties are not visible outside the class.
I am having some problems with my php code: All information returns but I cannot figure out why I am getting the error. For my index page I only inluded the line of code that is actually using that class there really is no other code other than some includes. Im sure it is how I built my __contstruct but i am not sure of the approriate way of doing it. I am missing something in how it is being called from the index page.
This line of code for my __construct works w/o error but I do not want the variable assigned in my class.
public function __construct(){
$this->user_id = '235454';
$this->user_type = 'Full Time Employee';
}
This is my Class
<?php
class User
{
protected $user_id;
protected $user_type;
protected $name;
public $first_name;
public $last_name;
public $email_address;
public function __construct($user_id){
$this->user_id = $user_id;
$this->user_type = 'Full Time Employee';
}
public function __set($name, $value){
$this->$name = $value;
}
public function __get($name){
return $this->$name;
}
public function __destroy(){
}
}
?>
This is my code from my index page:
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);
$employee_id = new User(2365);
$employee_type = new User();
echo 'Your employee ID is ' . '"' .$employee_id->user_id. '"' . ' your employement status is a n ' . '"' .$employee_type->user_type. '"';
echo '<br/>';
?>
The problem is:
$employee_type = new User();
the constructor expect one argument, but you send nothing.
Change
public function __construct($user_id) {
to
public function __construct($user_id = '') {
See the outputs
$employee_id = new User(2365);
echo $employee_id->user_id; // Output: 2365
echo $employee_id->user_type; // Output: Full Time Employee
$employee_type = new User();
echo $employee_type->user_id; // Output nothing
echo $employee_type->user_type; // Output: Full Time Employee
If you have one user, you can do this:
$employer = new User(2365);
$employer->user_type = 'A user type';
echo 'Your employee ID is "' . $employer->user_id . '" your employement status is "' . $employer->user_type . '"';
Which output:
Your employee ID is "2365" your employement status is "A user type"
I'm no PHP expert, but it looks like you are creating 2 new instances of class user, and on the second instatiation, you are not passing the user_id into the constructor:
$employee_id = new User(2365);
This, it would seem to me, is creating a new instance of User and assigning this instance to the variable $employee_id - I don't think this is what you want though?
$employee_type = new User();
This looks like you're instantiating another instance of User and assigning it to variable $employee_type - but you have called the constructor User() without passing in an ID as is required - hence the error (missing argument).
The reason your return script contents look OK is because the first instance of the User class has an ID (because you passed it in) and the second one has an employee type because this is set in the constructor.
Like I say, I don't know PHP but I'm guessing you want something more along the lines of:
$new_user = new User(2365);
echo 'Your employee ID is ' . '"' .$new_user->user_id. '"' . ' your employement status is a n ' . '"' .$new_user->employee_type. '"';
Here, you are instantiating a single instance of your user class assigned to the variable $new_user, and then accessing the properties of that single instance.
EDIT: .....Aaaaaaaaand - I was too slow :-)
for my question on how to use OOP in a beneficial way I assume as an example a BASKET to which its owner (Tom) having a certain ADDRESS (NY) can add ARTICLES (Bike, Car). Finally a BILL is printed containg all these information.
My problem is: How to handle collecting the information desired (here: owner, city, amount of items) from several objects? Because I think it is stupid to do this manually as done below (see 4.), isn't it? (even more since the amount of information increases in reality)
So what is the "clean way" for creating the bill / collecting the information needed in this example?
<?php
$a = new basket('Tom','NY');
$a->add_item("Bike",1.99);
$a->add_item("Car",2.99);
$b = new bill( $a );
$b->do_print();
1.
class basket {
private $owner = "";
private $addr = "";
private $articles = array();
function basket( $name, $city ) {
// Constructor
$this->owner = $name;
$this->addr = new addresse( $city );
}
function add_item( $name, $price ) {
$this->articles[] = new article( $name, $price );
}
function item_count() {
return count($this->articles);
}
function get_owner() {
return $this->owner;
}
function get_addr() {
return $this->addr;
}
}
2.
class addresse {
private $city;
function addresse( $city ) {
// Constructor
$this->city = $city;
}
function get_city() {
return $this->city;
}
}
3.
class article {
private $name = "";
private $price = "";
function article( $n, $p ) {
// Constructor
$this->name = $n;
$this->price = $p;
}
}
4.
class bill {
private $recipient = "";
private $city = "";
private $amount = "";
function bill( $basket_object ) {
$this->recipient = $basket_object->get_owner();
$this->city = $basket_object->get_addr()->get_city();
$this->amount = $basket_object->item_count();
}
function do_print () {
echo "Bill for " . $this->recipient . " living in " . $this->city . " for a total of " . $this->amount . " Items.";
}
}
If you do Tell Dont Ask, you would indeed add a render method to the bill to which you would pass an instance of BillRenderer. Bill would then tell BillRenderer how to render the Bill. This is in accordance with InformationExpert and High Cohesion principles that suggest methods to be on the objects with the most information to fulfill the task.
class Bill
{
…
public function renderAs(BillRenderer $billRenderer)
{
$billRenderer->setRecipient($this->owner);
$billRenderer->setAddress($this->address);
…
return $billRenderer->render();
}
}
BillRenderer (an interface) would then know the output format, e.g. you'd write concrete renderers for PlainText or HTML or PDF:
class TxtBillRenderer implements BillRenderer
{
…
public function render()
{
return sprintf('Invoice for %s, %s', $this->name, $this->address);
}
}
echo $bill->renderAs(new TxtBillRenderer);
If your Bill contains other objects, those would implement a renderAs method as well. The Bill would then pass the renderer down to these objects.
Both basket as well as bill could have a relation to a positions item - an object representing an ordered list of zero or more items with a count and price.
As such a list is an object of it's own it's easy to pass around:
$bill = new Bill($buyer, $address, $basket->getPositions());
However the printing of the bill should be done by the BillPrinter, because it's not the job of the bill to print itself:
$billPrinter = new BillPrinter($bill, $printerDevice);
$billPrinter->print();
First of all , in PHP5 the constructor it public function __construct(). What you are using there is the PHP4 way. And then ther eare other issues with your code:
instead of passing the name of the city to the Basket ( do you mean Cart ?), you should be creating the address object instance and passing it.
do not add items based on name an amount of money to the basket, instead add the whole instance of item, otherwise you will have a lot of problems when switching site language or currency.
the Articles (do you mean Items ?) should be created based on ID, not based on name. The reasons for that are the same as above + you will have issues with uniqueness. And then some of items might have lower price, when bought in combination. You need a way to safely identify them.
As for cleaning up the code there:
you should stop creating instance from given parameters in the constructor. While it is not always a bad thing, in your case you are making a mess there.
Bill should not be responsible for printing itself.
Something like :
class Basket
{
// -- other code
public function handleInvoice( Bill $invoice )
{
$invoice->chargeFor( $this->items );
$invoice->chargeTo( $this->account );
return $invoice->process();
}
}
.. then use it as
$cart = new Basket(..);
// some operation with it
$invoice = new Bill;
$cart->handleInvoice($invoice);
$printer = new PDFPrinter;
// OR new JpegPrinter; OR new FakePrinter OR anything else
$printer->print( $invoice );
This would give you an instance of Bill outside the class which then you can either print or send to someone.
Also , you might benefit from watching the willowing lecture:
Inheritance, Polymorphism, & Testing
Don't Look For Things!
Clean Code I: Arguments
Hello and thanks for being there,
I would like to pass a variable ($user) from a previous function to another one, but I need to use the arguments of the new function to pass the values that will render this new one.
Is there any way I can pass a variable from another function to a new function that only expects three arguments, and none of them is the variable from the previous function?
Example:
function my_function($country, $age, $colour) {
if ($user = true) {
echo "User is from " . $country . " and " . $age . " and his favourite colour is " . $colour;
}
}
my_function("italy", 19, "red");
It works if I put inside function my_function:
global $user;
but I believe using global variables is not a good practice.
Any idea on how to pass it as an argument? Should I just add it as another variable after $colour in the arguments of the new function?
Thanks a lot for your help :)
You can pass it as an argument, or better do this:
if ($user) my_function("italy", 19, "red");
since you don't have to use the $user variable inside that function.
You can use this function but best practice will be using class.
i .e if you call my_function("italy", 19, "red"), $user will be false by default
function my_function($country, $age, $colour, $user=false) {
if ($user == true) {
echo "User is from " $country . "and " . $age . " and his favourite colour is " . $colour;
}
}
my_function("italy", 19, "red",true);
Well, global variables are a bad practice, but a viable one in your case.
I would definitely recommend you looking into/using a Object Oriented approached.
There are really a bunch of different ways to achieve what your trying.
One way would be to encapsulate your code into a object.
<?php
class My_Cool_Class {
public $user = false;
public function myFunction($country, $age, $color) {
if ($this->user)
echo "User is from {$country} and {$age} years old and his favourite colour is {$color}";
}
}
$class = new My_Cool_Class();
$class->user = new User();
$class->myFunction("Italy", 19, "red");
Or you could implement a Singleton Pattern to easily get access to your object/functions from anywhere.
<?php
class My_Cool_Class {
public $user = false;
protected static $_instance;
public function getIntance() {
if(!self::$_instance)
self::$_instance = new self();
return self::$_instance;
}
public function setUser($user) {
$this->user = $user;
}
public function myFunction($country, $age, $color) {
if ($this->user)
echo "User is from {$country} and {$age} years old and his favourite colour is {$color}";
}
}
//Set User from anywhere with this
My_Cool_Class::getInstance()->setUser($user);
//Call your function anywhere with this.
My_Cool_Class::getInstance()->myFunction("Italy", 19, "red");
If your previous function is something like this:
/**
* Callback function for so_user_data() that tells if we want to give you info about the user or not.
* #param (string) $user | Accepts a Username as input
* #return (boolean) | true if the User is 'Rob'
*/
function so_user_fn( $user )
{
$allowed_users = array(
'Rob'
,'Jay'
,'Silent Bob'
);
if ( in_array $user, $allowed_users ) )
return true;
// false if not 'Rob'
return false;
}
/**
* Shows the country, age & fav. colour of a user or denies displaying this information
* if the user is not a public v.i.p. or someone other we want to give you info about.
* #uses so_user_fn() | used to determine if the user is 'Rob'
* #param (string) $user | Username
* #param (string) $country | (optional) Country of origin
* #param (integer) $age | (optional) Age of the user
* #param (string) $colour | (optional) Fav. Colour
*/
function so_user_data( $user, $country = 'an unknown country', $age = 'unknown', $colour = 'not known' )
{
$output = "$user is from {$country} and {$age} years old. His favourite colour is {$colour}.";
// Only print the output if the user is 'Rob'
if ( so_user_test( $user ) )
return print $output;
return print 'We are not allowed to give you information about this user.';
}
You can call it like this:
so_user_data( 'Fancy Franzy' );
// outputs: We are not allowed to give you information about this user.
so_user_data( 'Rob' );
// outputs: Rob is from an unknown country and unknown years old. His favourite colour is not known.
so_user_data( 'Silent Bob', 'U.S.A.', '38', 'brown' );
// outputs: Silent Bob is from U.S.A. and 38 years old. His favourite colour is brown.