This question already has answers here:
Fatal error: Declaration of .. must be compatible with .. PHP
(6 answers)
Closed last year.
VSCode doesn't accept a child and parent method with the same name but they have the same purpose.
The book I use doesn't use different name for this exercise and I don't understand why it doesn't work with me.
I found a solution by giving a different name to the child method but it doesn't help me to understand the problem.
Index.php
function monAutoLoad($class) {
include(str_replace("\\", "/", $class). ".php");
}
spl_autoload_register('monAutoLoad');
use MesProduits\Produit;
$ordinateur = new Produit("ordinateur",10,1200,false);
echo $ordinateur . "<br>";
echo $ordinateur->supprimerProduit(5) . "<br>";
use MesProduits\ProduitParLots;
$cartouchesEncre=new ProduitParLots("Cartouches d'encre",3,50,false);
$cartouchesEncre->setNbArticlesParLot(10);
$cartouchesEncre->ajouterProduit(6);
echo $cartouchesEncre . "<br>";
Produit.php (parent class file)
namespace MesProduits; //donner le même nom que le dossier parent
class Produit{
protected $nom = "mon produit";
protected $quantite = 10;
protected $prix = 120;
protected $rupture = false;
function __construct($nom,$quantite,$prix,$rupture)
{
$this->nom=$nom;
$this->quantite=$quantite;
$this->prix=$prix;
$this->$rupture=$rupture;
}
function __toString(){
return "nom: " . $this->nom . "<br>".
"quantité: " . $this->quantite . "<br>".
"prix: " . $this->prix . "<br>".
(($this->rupture)? "no stock <br>" : "in stock <br>");
}
function ajouterProduit($quantite){ //parent method and I want the same name in the child file
$this->quantite+=$quantite;
if($this->quantite >=0){
$this->rupture = false;
}
return "a product has been add <br>" .
"there is: " . $this->quantite . " in stock <br>";
}
function supprimerProduit($quantite){
$this->quantite-=$quantite;
if($this->quantite <=0){
$this->rupture = true;
}
return "a product has been removed <br>" .
"there is " . $this->quantite . " in stock <br>";
}
}
ProduitParLots.php (child file class)
namespace MesProduits;
class ProduitParLots extends Produit{
private $nbArticlesParLot;
function getNbArticlesParLot(){
return $this->nbArticlesParLot;
}
function setNbArticlesParLot($valeur){
if(!is_integer($valeur)){
echo "the property must be an integer <br>";
}else{
$this->nbArticlesParLot=$valeur;
}
}
function ajouterProduit2(){ //need to choose a different name for the child method
$this->quantite+=$this->nbArticlesParLot;
if($this->quantite>0) $this->rupture=false;
}
}
This is because the "child" method has not the same signature as the parent method. You missed the $quantite parameter.
class ProduitParLots extends Produit
{
function ajouterProduit($quantite) { /* ... */ }
}
Related
Tl;dr: at the bottom
Setup:
I have a cron job that calls a PHP script to handle some Backend tasks. For simplicity, the cron job redirects all output to a log file. Because this matters to my actual question found below, here's the sanitized format of the cron job:
15 4 * * * php /usr/local/bin/myScript.php >> /home/$USER/scriptLogs/myScript.log 2>&1
I'm new-ish to OOP and I'm being tasked with learning it as I go, and for myScript.php, I'm doing some data imports that require querying the DB to validate the data prior to its import and I'm supposed to log every transaction. We recently moved from 5.6 to 7.2 and part of task at hand is to use 7.2's new features as we refactor.
The refactor itself is to take all of the duplicated code and move it to classes to obey the DRY principle.
Previously, it looked something like this:
<?php namespace CronJobs
use PDO;
use Exception;
class JobAt415 {
private function getDBconnection()
{
// connects to a DB through environment variable set in a config file
return $db;
}
public function query1($parameter1, $parameter2, $inclusionParameter)
{
$sql = "SELECT " . $parameter1 . ", ". $parameter2 . " FROM `foo`.`bar` WHERE " . $inclusionParmeter " IS NOT NULL;";
try
{
$db = $this->getDBconnection();
echo '[' . strftime("%c") . '] Running query 1' . PHP_EOL;
$resultDictionary = $db->query($sql)->fetchall(PDO::FETCH_KEY_PAIR)
return $resultDictionary;
}
catch (Exception $e)
{
echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
echo $e->getMessage();
return null;
}
}
public function query2($parameter1, $parameter3)
{
$sql = "SELECT " . $parameter1 . " FROM `foo`.`bar` WHERE " . $parameter3 " > 0;";
try
{
$db = $this->getDBconnection();
echo '[' . strftime("%c") . '] Running query 1' . PHP_EOL;
$resultDictionary = $db->query($sql)->fetchall()
return $resultArray;
}
catch (Exception $e)
{
echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
echo $e->getMessage();
return null;
}
}
}
Post-Refactor:
<?php namespace CronJobs
use PDO;
use Exception;
Class DbConnectionFactory {
protected $dbConnection;
public function __construct()
{
$this->dbConnection = $this->createConnection();
}
public function runQuery($sql, ...$queryDescriptor)
{
try
{
$descriptor = $queryDescriptor ? (string) $queryDescriptor : $sql;
echo '[' . strftime("%c") . '] Running query ' . "$descriptor" . PHP_EOL;
$resultPending = $this->dbConnection->query($sql);
echo '[' . strftime("%c") . '] Query successful.' . PHP_EOL;
return $resultPending;
}
catch (Exception $e)
{
echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
echo $e->getMessage();
return null;
}
}
public function runQueryFetchDictionary($sql, ...$queryDescriptor)
{
$description = (string) $queryDescriptor;
$fetchAll = $this->runQuery($sql, $description)->fetchall(PDO::FETCH_KEY_PAIR);
return $fetchAll;
}
// In the JobAt415 class
private function runQuery1()
{
$sql = 'SELECT `parameter1`, `parameter2` FROM `foo`.`bar` WHERE `baz` IS NOT NULL;';
$description = 'p1, p2 :: baz != NULL';
$p1Dictionary = $this->db->runQueryFetchDictionary($sql, $descripton); // $this->db is an instantiation of the DbConnectionFactory class
So, now I just pass the SQL query as a parameter and a description of what is being queried to be echoed to the log, and I don't have 19 try/catch blocks in the code or a bunch of duplicated code that I've removed from this example.
Unfortunately, as I'm stepping through the code with XDebug, the optional parameter $queryDescriptor is being converted from a string to an array. I've tried multiple ways of passing it, casting it, and/or defining it and get the same result: $queryDescriptor is an array. At one point, casting it to a string returned the value of "Array".
When I checked the PHP website, I found this:
Note:
The behaviour of an automatic conversion to array is currently undefined.
Emphasis mine.
I don't want any conversion. So, how do I prevent this? Does anyone see what I'm missing? Why doesn't the $sql string get converted to an array but the $queryDescriptor always get converted?
Tl;dr:
Why is my string now an array?
Because by adding a parameter like ...$queryDescriptor you tell PHP that there can be endless parameters. This is because of the ... in front of the variable name. That's why PHP changes the type to an array.
Otherwise how could you handle the number of possibly thousand of parameters?
https://secure.php.net/manual/en/functions.arguments.php#functions.variable-arg-list
//You tell PHP that there can be a variable number of parameters by adding '...' in front of the variable name
function foo(...$bar) {
//You get an array holding all the passed parameters
foreach($bar as $arg) {
//By stepping through it you get all the parameters
echo $arg;
}
}
Or of course you can get the parameters by their indexes.
$bar[0]; //returns the first passed parameter
Below is the implementation in PHP. I aim to have a different coupon code and a different discount returned, based on the type of book (vintage or new).
<?php
interface BookOffer {
function generateCoupon();
function generateDiscount();
}
class VintageBookOffer implements BookOffer {
function generateCoupon() {
return "VINTAGECOUPONCODE";
}
function generateDiscount() {
return 10.0;
}
}
class NewBookOffer implements BookOffer {
function generateCoupon() {
return "NEWBOOKCOUPONCODE";
}
function generateDiscount() {
return 5.0;
}
}
class OfferGenerator {
function generateOffer($bookType) {
if($bookType == "vintage") {
$bookObject = new VintageBookOffer();
}
else if($bookType == "newbook") {
$bookObject = new NewBookOffer();
}
return $bookObject;
}
}
$bookType1 = "vintage";
$bookType2 = "newbook";
$offerGenerator = new OfferGenerator();
$bookOffer1 = $offerGenerator->generateOffer($bookType1);
$bookOffer2 = $offerGenerator->generateOffer($bookType2);
echo "You chose book type " . $bookType1 . ". Your coupon code is " . $bookOffer1->generateDiscount() . ", and your discount is " . $bookOffer1->generateCoupon();
echo "You chose book type " . $bookType2 . ". Your coupon code is " . $bookOffer2->generateDiscount() . ", and your discount is " . $bookOffer2->generateCoupon();
?>
Does this look correct? I believe it is. But any feedback from the community would be welcome. The only reason I think it might be incorrect is because it does not use type hinting, which is frequently seen in the Strategy Pattern.
So I have this small class to store properties of a fluid together.
<?php
// Two Phase flow vertical pressure differential calculator
class Fluid {
public $name;
public $re;
public $rho;
public $j;
public $D;
public $f;
public $dPdZ;
public $w=0;
public function _construct($arg1,$re,$rho,$j,$D){
//store inputs
$this->name=$arg1;
$this->re=$re;
$this->rho=$rho;
$this->j=$j;
$this->D=$D;
//calculate F value
if($re < 1000){
$this->f = 16.0 / $re;
}elseif($re > 2000){
$this->f = .046 / pow($re, .2);
}else{
$this->w= ($re-1000)/1000;
$this->f= $this->w*16.0/$re+(1-$this->w)*.046/pow($re, .2);
}
//calculate Vertical pressure drop
$this->dPdZ=2*$this->f*$rho*$j*$j/$D+$rho*9.8;
}
// print contents of object
public function printOut(){
echo "For " . $this->name . "\r\n";
echo "Inputs: re=" . $this->re . " rho=".$this->rho . " j=" . $this->j . " D=" . $this->D . "\r\n";
echo "Intermediates: f=" . $this->f . " w=" . $this->w . " dP/dZ=" . $this->dPdZ . "\r\n";
}
}
//create Fluid Objects (currently static inputs)
$liquid= new Fluid("liquid",111714.4,934.1,.5,.0508);
$gas= new Fluid("gas",1201.2,.96,.5,.0508);
//Find C
if($liquid->re > 1500&& $gas->re > 1500){
$C=20;
}else if($liquid->re < 1500 && $gas->re > 1500){
$C=12;
}else if ($liquid->re > 1500 && $gas->re < 1500){
$C=10;
}else{
$C=5;
}
//calculate pressure differential
$dPdZ=$liquid->dPdZ+$gas->dPdZ+$C*pow($liquid->dPdZ*$gas->dPdZ,.5);
//print results
$liquid->printOut();
$gas->printOut();
echo "Yields: dP/dZ=". $dPdZ . " C=" . $C;
?>
However, when I get to the end it prints
For
Inputs: re= rho= j= D=
Intermediates: f= w=0 dP/dZ=
For
Inputs: re= rho= j= D=
Intermediates: f= w=0 dP/dZ=
Yields: dP/dZ=0 C=5
ignoring all values from class Fluid. I am under the assumption that the values are all NULL and my initialization is incorrect as I am new to PHP. However, I can't figure out what is wrong with my syntax.
The problem is that you are one underscore short in the __construct method.
_construct should be __construct.
There is a syntax error in your code you need to make the double underscore construct for calling constructor
__construct
Your constructor is not being called because of this syntax error on object creation.
I am working on displaying information from my database. When I did print_r in the model/itemTile.php below to check on my array, $this->display, I noticed it had stored 2 copies of the data from my database. I checked my database, and there was definitely only one copy of the data.
I created a counter variable, $this->counter, to see what the surrounding while loop was doing. The original data had 6 non-duplicating rows. As you may see in the jpg attached below, the program increments and echo the counter to 6, then it does the "print_r($this->display)" line that is outside of the while loop, then for some strange reason goes back to the while loop, increment the counter, and print the $this->counter and $this->display again!
I can remove the duplicate, but I would much prefer to figure out why exactly there are two copies of the value to begin with.
Since this was originally a PHP class project that focus on MVC, everything is placed into controller, model, and view. I have included the relevant model and view code below:
Jpg:
PHP Site
model/itemTile.php
<?php
require_once('siteInfo.php');
class itemTile implements siteInfo {
private $term;
private $session;
private $result;
private $display = array();
private $counter = 0;
public function __construct($session) {
$this->session = $session;
}
public function getContent() {
$this->result = $this->session->db->prepare("SELECT productName, sciName, price FROM products");
$this->result->execute();
$this->result->bind_result($pN, $sN, $pz);
while ($this->result->fetch()) {
if (array_key_exists($pN, $this->display)) {
$this->display[$pN]["price"][] = $pz;
} else {
$this->display += [
$pN => [ //Product Name was used to id array because not all item have sciName,
"sciName" => [$sN], //and not all item have only 1 sku (1 item with different size = multiple pid).
"price" => [$pz]
]
];
}
$this->counter++;
echo $this->counter . "<br />";
}
$this->result->close();
print_r($this->display);
echo "<br />";
}
public function setContent() {
$this->getContent();
return $this->display;
}
}
?>
view/itemTile.php
<?php
class itemTileView {
private $model;
public function __construct(itemTile $model) {
$this->model = $model;
}
public function output(){
foreach ($this->model->setContent() as $item => $detail) {
$itemLink = preg_replace('/\s+/','_', $item);
echo "<div class= 'tileSpace'>";
echo "<a href='itemPages/" . $itemLink. "/home.php'>";
echo "<img alt='" . $item . "' src='itemPages/" . $itemLink . "/thumbnail.jpg' width='100' height='100'>";
echo "</a>";
echo "<p>" . $item . ": " . $detail["sciName"][0] . "</p>";
if (count($detail["price"]) > 1) {
echo "<p>" . min($detail["price"]). " - " . max($detail["price"]). "</p>";
} else {
echo "<p>" . $detail["price"][0] . "</p>";
}
echo "</div>";
}
}
}
?>
Can anyone spot where is the problem occurring?
use php function array_unique();
array_unique($arrayname);
using this you will get unique values from array.it avoids duplicate values
Well, ive been trying to get my crm to print multiple contacts for each company but i cant get it to work
Company is a class,companycontactis a class
//class called company
function __construct($idklanten,$naam,$adres,$postcode,$stad,$contacten){
$this->idklanten=$idklanten;
$this->naam=$naam;
$this->adres=$adres;
$this->postcode=$postcode;
$this->stad=$stad;
$this->contacten=$contacten;
}
//class called contact
function __construct($idcontactklanten,$voornaam,$tussenvoegsel,$achternaam,$tel,$email,$klantID){
$this->idcontactklanten=$idcontactklanten;
$this->voornaam=$voornaam;
$this->tussenvoegsel=$tussenvoegsel;
$this->achternaam=$achternaam;
$this->tel=$tel;
$this->email=$email;
$this->klantID=$klantID;
}
//getname for a contact
function getNaam() {
if(strlen($this->gettussenvoegsel()) == 0) {
return $this->getvoornaam()." ".$this->getachternaam()."";
}
else {
return $this->getvoornaam() . " " . $this->gettussenvoegsel() . " " . $this->getachternaam();
}
}
//function for getting the names from my object company,array with objects of contacts
function getcontacten(){
$ct=$this->contacten[$teller];
$txt="";
for($teller=0;$teller<10;$teller++){
$txt+=$ct->getNaam()."<br>";
}
return $txt;
}
then on my index page when i call getcontacten() it does not work comparing to my other get function which do work. it just outputs a 0
Any help is appreciated
Your biggest error would be the following:
$txt+=$ct->getNaam()."<br>";
Should be
$txt.=$ct->getNaam()."<br>";
Because to append to a string you use ".=", not "+=".
Also I don't know if the other part of you code works, I would write something like the following:
$txt = "";
foreach ($this->contacten as $ct){
$txt .= $ct->getNaam() . "<br />";
}
return $txt;
or
$txt = "";
for ($i = 0; $i < count($this->contacten); $i++){
$txt .= $this->contacten[$i]->getNaam() . "<br />";
}
return $txt;