PHP
--
Questions
--
Followers
Top Experts
I have a MySQL table for each type of enrollment and a corresponding PHP object specific to each to handle CRUD for each table.
Both objects inherit from a parent object called sqlTable which provides MySQL access primitives (e.g., self::findBySql() ) enabling child objects to access any MySQL table in our database. IOW, the sqlTable object is the generic toolbox and table-specific child objects are tailored to the unique functional requirements of each.
In this particular case, the methods for determining credits attempted and earned are identical in name and function within each enrollment-specific object.
I need to calculate aggregate credits attempted/earned, grade points earned, and GPA for each enrollment type. The methods I've created for calculating them for each class of enrollment are absolutely identical.
I want to maintain a single block of code rather than trying to keep 2 identical ones in synch. IOW, I would like to have a single object called Academics which extends either parent table dynamically, rather than having two identical Academics objects, one for each class of enrollment.
Here's what I'm talking about:
Current Situation
class Academics1 extends Enrollment1 {
method1();
method2();
…
}
class Academics2 extends Enrollment2 {
identical method1();
identical method2();
…
}Option#1
"Some code" ascertains enrollment type using a variable or passed argument.
It produces a result I will call "parent_object" having
1 of 2 possible values: Enrollment1 or Enrollment2.
class Academics extends parent_object {
method1();
method2();
…
}Option #2
"Some code" ascertains enrollment type using a variable or passed argument.
It produces a result I will call $enroll_type having
1 of 2 possible values: TRUE or FALSE, with TRUE = Enrollment1
and FALSE = Enrollment2.
if( $enroll_type )
class Academics extends Enrollment1 {
method1();
method2();
…
}
else
class Academics extends Enrollment2 {
method1();
method2();
…
}It is possible traits or interfaces could be used for the "some code" sections in the options above, but I've never been taught how to use either and the documentation at php.net amounts to "Hello, world!" kinds of examples from which I cannot seem to connect the conceptual dots required to achieve my goal —assuming of course either is a viable solution, that is!
Questions
1. Is something akin to what I have described in Options 1 or 2 doable in PHP 7.3 or newer?
2. If so, what does the code look like?
Thanks!
Zero AI Policy
We believe in human intelligence. Our moderation policy strictly prohibits the use of LLM content in our Q&A threads.
class BaseEnrollment
{
method1();
method2();
}
class Enrollment1 extends BaseEnrollment
{
...methods unique to enrollment type 1...
}
class Enrollment2 extends BaseEnrollment
{
...methods unique to enrollment type 2...
}
class Academics1 extends Enrollment1
{
... should inherit method1, method2, and anything specific to Enrollment1...
}
class Academics2 extends Enrollment2
{
... should inherit method1, method2, and anything specific to Enrollment2...
}
<?php
trait StuffYouCanDoWithMostAnimals
{
function pet()
{
return "The " . __CLASS__ . ", " . $this->name . ", likes it when you pet them!";
}
function lick()
{
return "The " . __CLASS__ . ", " . $this->name . ", tastes funny but it doesn't bite you back. Probably not the smartest decision you've ever made.";
}
}
class Animal
{
public $name = "an animal";
}
class DangerousAnimal extends Animal
{
public $name = "a dangerous animal"; // Overrides the base Animal $name
// Some methods that simply HAPPEN to use the same names as the ones in the trait,
// but they're not necessarily required. If you left off pet() and then you tried
// to pet() one of these, then it would throw an error.
function pet()
{
return $this->diefrom("pet");
}
function lick()
{
return $this->diefrom("lick");
}
function diefrom($action)
{
return "The " . __CLASS__ . ", " . $this->name . ", kills you for daring to " . $action . " it.";
}
}
class ApatheticAnimal extends Animal
{
public $name = "an apathetic animal"; // Overrides the base Animal $name
use StuffYouCanDoWithMostAnimals;
function lick() // Override the lick() function from the trait
{
return "The " . __CLASS__ . ", " . $this->name . ", looks at you strangely, but it doesn't bite you back.";
}
}
class FriendlyAnimal extends Animal
{
public $name = "a friendly animal"; // Overrides the base Animal $name
use StuffYouCanDoWithMostAnimals;
}
class Dog extends FriendlyAnimal
{
public $name = "a dog"; // Overrides the FriendlyAnimal $name
}
class Bear extends DangerousAnimal
{
public $name = "a bear"; // Overrides the DangerousAnimal $name
}
class Sloth extends ApatheticAnimal
{
public $name = "a sloth"; // Overrides the ApatheticAnimal $name
}
$dog = new Dog();
echo $dog->pet() . "<br />\n";
echo $dog->lick() . "<br />\n";
$bear = new Bear();
echo $bear->pet() . "<br />\n";
echo $bear->lick() . "<br />\n";
$sloth = new Sloth();
echo $sloth->pet() . "<br />\n";
echo $sloth->lick() . "<br />\n";The output should be:The FriendlyAnimal, a dog, likes it when you pet them!
The FriendlyAnimal, a dog, tastes funny but it doesn't bite you back.
The DangerousAnimal, a bear, kills you for daring to pet it.
The DangerousAnimal, a bear, kills you for daring to lick it.
The ApatheticAnimal, a sloth, likes it when you pet them!
The ApatheticAnimal, a sloth, looks at you strangely, but it doesn't bite you back.
class Enrollment1 extends sqlTable
class Enrollment2 extends sqlTable
clasa Academics1 extends Enrollment1
class Academics2 extends Enrollment2The tables and the fieldnames of enrollments1 and enrollments2 are similar but significantly different, too different to combine the two into one table with some field used to differentiate between the 2 record types. Each child object of sqlTable has its respective table fields as its attributes, so there are more than just methods involved in each. For example, there is a credits field in the table, so there is a corresponding $credits attribute containing that field's value once the object is instanciated which can then be manipulated by getCredits(), setCredits(), and used for calculation by getCreditsAttempted() and getCreditsEarned().What I'm trying to do is merge is Academics1 and Academics2 into one file (since they are identical).
Your second example illustrating traits presents the same problem I'm having trying to make the conceptual leap between the documentation on php.net.
Can you give me a specific example of actual PHP code where a trait can be used to dynamically switch which object (Enrollment1 or Enrollment2) the Academics object will extend? And how will I specify to the trait which it will choose?






EARN REWARDS FOR ASKING, ANSWERING, AND MORE.
Earn free swag for participating on the platform.
Academics1.php:
class Academics extends Enrollment1
{
...
}Academics2.php:
class Academics extends Enrollment2
{
...
}... and then you can dynamically include() the appropriate file, but that's pretty messy and you'd be limited to one type of Academics class per execution of your script (so once you defined it as extending from Enrollment1 during the script execution, you couldn't go back during the same execution and make it extend Enrollment2).
Another way to think about them:
traits - are basically like being able to include() a portion of a class (methods and properties) into other classes (properties can't conflict, though - a trait can only define a property that the class doesn't already define)
interfaces - won't help you here. Interfaces are just code-less skeletons that basically remind a developer of all the methods he/she has to define in a class (a little more to it than that, but for right now, the point is that it's not going to help you with what you're looking to do here)..
Personally, if you have a dependency on trait-defined properties, I would make heavy use of getters/setters to avoid conflicts. Example:
trait MyTrait1
{
public $myTrait1Props = array("foo" => "bar");
public function getFoo() { return $this->myTrait1Props["foo"]; }
public function setFoo($value) { $this->myTrait1Props["foo"] = $value; }
}
trait MyTrait2
{
public $myTrait2Props = array("hello" => "world");
public function getHello() { return $this->myTrait2Props["hello"]; }
public function setHello($value) { $this->myTrait2Props["hello"] = $value; }
}
class Blah
{
public $aBlahField = "apple";
use MyTrait1;
use MyTrait2;
}
$blah = new Blah();
echo $blah->aBlahField; // "apple"
echo $blah->getFoo(); // "bar"
echo $blah->getHello (); // "world "
trait Academics {
public static function sumXferCredits() {
}
public static function sumNonXferCredits {
}
public static function sumTotalCredits {
}
}
class Enrollment1 extends sqlTable {
use Academics;
$attributes
…
public function method1() {
}
public function method2() {
}
…
}
class Enrollment12 extends sqlTable {
use Academics;
$attributes
…
public function method1() {
}
public function method2() {
}
…
}The Academics trait would reside in its own file and included prior to the other two.
What do you think? Would this work?
Thanks!
Strategy: you have a separate concrete class for each table, but their methods derive from a common interface. The common interface methods are used to calculate the aggreate values in a separate calulcation class.
Template: you have a base class, which defines the methods getting the concrete values as stubs. And the template class does also the actual calculations. Then you derive a concrete class for each table and just fill in the stub methods to return the values depending on the table.
Caveat: What pattern is better suited depends on your actual use-case and data model. Here it is important, what kind of relation does logically exists and is really implemented. Most common pattern is sub- and super-classing. But both are hard to implement correctly in MySQL.
Thus maybe you need to look also into the builder or factory method for retreving the correct concrete classes.

Get a FREE t-shirt when you ask your first question.
We believe in human intelligence. Our moderation policy strictly prohibits the use of LLM content in our Q&A threads.
At this stage, I think you'd need to provide some use cases to explain the different inputs and expected outputs. For example, "John is an Enrollment1 student, and his grades should be calculated like this..."
"Mary is an Enrollment2 student and her grades should be calculated like this..."
"All 3 types of enrollment students should share function X, which acts identical for the student, but function X can't be defined in a parent class because..."
...etc...
PHP
--
Questions
--
Followers
Top Experts
PHP is a widely-used server-side scripting language especially suited for web development, powering tens of millions of sites from Facebook to personal WordPress blogs. PHP is often paired with the MySQL relational database, but includes support for most other mainstream databases. By utilizing different Server APIs, PHP can work on many different web servers as a server-side scripting language.