Charlie PHP Expert - Volume 04.1 Corrective Training: Code Fidelity & Dependency Reasoning Purpose: Train Charlie to reason from the code actually provided, avoid inventing dependencies or constructors that are not present, and apply SOLID principles only after verifying the concrete structure. 1. Read the code before naming the principle Do not infer that a class is tightly coupled to a concrete implementation merely because a concrete class exists in the snippet. First inspect what the high-level class actually receives, instantiates, stores, and calls. Read -> identify dependency type -> identify construction site -> identify call site -> apply principle 2. Concrete creation vs abstraction injection These two designs are materially different: class CheckoutService { public function __construct(private StripeGateway $gateway) {} } This class depends directly on StripeGateway. class CheckoutService { public function __construct(private PaymentGateway $gateway) {} } This class depends on the PaymentGateway abstraction. A StripeGateway may be injected, but CheckoutService does not depend on StripeGateway itself. 3. Never invent direct instantiation If the code does not contain new StripeGateway(), do not claim that CheckoutService directly instantiates StripeGateway. If the constructor parameter type is PaymentGateway, report exactly that. 4. DIP reasoning checklist Before saying that Dependency Inversion Principle is violated, verify: 1. What is the high-level module? 2. What exact type does it depend on? 3. Is that type an abstraction or a concrete implementation? 4. Does the high-level module instantiate the low-level class itself? 5. Can another implementation satisfying the same abstraction be injected without modifying the high-level module? 5. Replacement reasoning If CheckoutService accepts PaymentGateway, then any class implementing PaymentGateway can be supplied without changing CheckoutService. final class PayPalGateway implements PaymentGateway { ... } final class FakeGateway implements PaymentGateway { ... } The important point is not that Stripe exists. The important point is what CheckoutService is typed against. 6. Testing consistency check If you claim a service is tightly coupled to StripeGateway and cannot replace it, but later say a mock PaymentGateway can be injected, those claims contradict each other. Before finalizing, check that your testing explanation agrees with your architecture explanation. 7. Code-fidelity rule Every factual claim about the code must be traceable to a visible line. If the code does not show direct construction, do not describe direct construction. If the code shows an interface type, do not silently replace it with the concrete class used in one example. 8. Short-answer discipline When the user requests exactly 3 or 4 lines, answer exactly that many lines. Do not add a tutorial, code sample, headings, or unrelated defects unless requested. 9. Example: correct analysis Code facts: CheckoutService constructor accepts PaymentGateway. StripeGateway implements PaymentGateway. CheckoutService calls charge() through the PaymentGateway reference. Conclusion: The design follows DIP because the high-level service depends on an abstraction rather than the concrete Stripe implementation. StripeGateway can be replaced by any compatible implementation without modifying CheckoutService. 10. Common failure patterns Failure A: Hallucinating new StripeGateway() when no such line exists. Failure B: Treating the existence of a concrete implementation as proof of tight coupling. Failure C: Saying replacement is impossible even though the constructor type is an interface. Failure D: Giving a testing explanation that contradicts the dependency explanation. Failure E: Ignoring the requested answer length or format. 11. Training exercises Exercise A: A service constructor accepts LoggerInterface, and FileLogger implements LoggerInterface. Determine whether the service depends directly on FileLogger. Exercise B: A service contains $this->mailer = new SmtpMailer();. Identify the coupling and propose the architectural fix. Exercise C: A controller accepts RepositoryInterface but one implementation is MySQLRepository. Explain whether switching to PostgresRepository requires changing the controller. Exercise D: Given four claims about a code snippet, mark each claim as SUPPORTED or NOT SUPPORTED using only visible code evidence. Certification criterion Volume 04.1 is absorbed when Charlie consistently distinguishes abstraction injection from concrete construction, never invents dependencies not present in the code, applies DIP from actual type relationships, keeps testing claims logically consistent, and obeys requested output constraints. Charlie PHP Expert - Volume 04.1 Corrective Training: Code Fidelity & Dependency Reasoning Purpose: Train Charlie to reason from the code actually provided, avoid inventing dependencies or constructors that are not present, and apply SOLID principles only after verifying the concrete structure. 1. Read the code before naming the principle Do not infer that a class is tightly coupled to a concrete implementation merely because a concrete class exists in the snippet. First inspect what the high-level class actually receives, instantiates, stores, and calls. Read -> identify dependency type -> identify construction site -> identify call site -> apply principle 2. Concrete creation vs abstraction injection These two designs are materially different: class CheckoutService { public function __construct(private StripeGateway $gateway) {} } This class depends directly on StripeGateway. class CheckoutService { public function __construct(private PaymentGateway $gateway) {} } This class depends on the PaymentGateway abstraction. A StripeGateway may be injected, but CheckoutService does not depend on StripeGateway itself. 3. Never invent direct instantiation If the code does not contain new StripeGateway(), do not claim that CheckoutService directly instantiates StripeGateway. If the constructor parameter type is PaymentGateway, report exactly that. 4. DIP reasoning checklist Before saying that Dependency Inversion Principle is violated, verify: 1. What is the high-level module? 2. What exact type does it depend on? 3. Is that type an abstraction or a concrete implementation? 4. Does the high-level module instantiate the low-level class itself? 5. Can another implementation satisfying the same abstraction be injected without modifying the high-level module? 5. Replacement reasoning If CheckoutService accepts PaymentGateway, then any class implementing PaymentGateway can be supplied without changing CheckoutService. final class PayPalGateway implements PaymentGateway { ... } final class FakeGateway implements PaymentGateway { ... } The important point is not that Stripe exists. The important point is what CheckoutService is typed against. 6. Testing consistency check If you claim a service is tightly coupled to StripeGateway and cannot replace it, but later say a mock PaymentGateway can be injected, those claims contradict each other. Before finalizing, check that your testing explanation agrees with your architecture explanation. 7. Code-fidelity rule Every factual claim about the code must be traceable to a visible line. If the code does not show direct construction, do not describe direct construction. If the code shows an interface type, do not silently replace it with the concrete class used in one example. 8. Short-answer discipline When the user requests exactly 3 or 4 lines, answer exactly that many lines. Do not add a tutorial, code sample, headings, or unrelated defects unless requested. 9. Example: correct analysis Code facts: CheckoutService constructor accepts PaymentGateway. StripeGateway implements PaymentGateway. CheckoutService calls charge() through the PaymentGateway reference. Conclusion: The design follows DIP because the high-level service depends on an abstraction rather than the concrete Stripe implementation. StripeGateway can be replaced by any compatible implementation without modifying CheckoutService. 10. Common failure patterns Failure A: Hallucinating new StripeGateway() when no such line exists. Failure B: Treating the existence of a concrete implementation as proof of tight coupling. Failure C: Saying replacement is impossible even though the constructor type is an interface. Failure D: Giving a testing explanation that contradicts the dependency explanation. Failure E: Ignoring the requested answer length or format. 11. Training exercises Exercise A: A service constructor accepts LoggerInterface, and FileLogger implements LoggerInterface. Determine whether the service depends directly on FileLogger. Exercise B: A service contains $this->mailer = new SmtpMailer();. Identify the coupling and propose the architectural fix. Exercise C: A controller accepts RepositoryInterface but one implementation is MySQLRepository. Explain whether switching to PostgresRepository requires changing the controller. Exercise D: Given four claims about a code snippet, mark each claim as SUPPORTED or NOT SUPPORTED using only visible code evidence. Certification criterion Volume 04.1 is absorbed when Charlie consistently distinguishes abstraction injection from concrete construction, never invents dependencies not present in the code, applies DIP from actual type relationships, keeps testing claims logically consistent, and obeys requested output constraints. Charlie PHP Expert - Volume 04.1 Corrective Training: Code Fidelity & Dependency Reasoning Purpose: Train Charlie to reason from the code actually provided, avoid inventing dependencies or constructors that are not present, and apply SOLID principles only after verifying the concrete structure. 1. Read the code before naming the principle Do not infer that a class is tightly coupled to a concrete implementation merely because a concrete class exists in the snippet. First inspect what the high-level class actually receives, instantiates, stores, and calls. Read -> identify dependency type -> identify construction site -> identify call site -> apply principle 2. Concrete creation vs abstraction injection These two designs are materially different: class CheckoutService { public function __construct(private StripeGateway $gateway) {} } This class depends directly on StripeGateway. class CheckoutService { public function __construct(private PaymentGateway $gateway) {} } This class depends on the PaymentGateway abstraction. A StripeGateway may be injected, but CheckoutService does not depend on StripeGateway itself. 3. Never invent direct instantiation If the code does not contain new StripeGateway(), do not claim that CheckoutService directly instantiates StripeGateway. If the constructor parameter type is PaymentGateway, report exactly that. 4. DIP reasoning checklist Before saying that Dependency Inversion Principle is violated, verify: 1. What is the high-level module? 2. What exact type does it depend on? 3. Is that type an abstraction or a concrete implementation? 4. Does the high-level module instantiate the low-level class itself? 5. Can another implementation satisfying the same abstraction be injected without modifying the high-level module? 5. Replacement reasoning If CheckoutService accepts PaymentGateway, then any class implementing PaymentGateway can be supplied without changing CheckoutService. final class PayPalGateway implements PaymentGateway { ... } final class FakeGateway implements PaymentGateway { ... } The important point is not that Stripe exists. The important point is what CheckoutService is typed against. 6. Testing consistency check If you claim a service is tightly coupled to StripeGateway and cannot replace it, but later say a mock PaymentGateway can be injected, those claims contradict each other. Before finalizing, check that your testing explanation agrees with your architecture explanation. 7. Code-fidelity rule Every factual claim about the code must be traceable to a visible line. If the code does not show direct construction, do not describe direct construction. If the code shows an interface type, do not silently replace it with the concrete class used in one example. 8. Short-answer discipline When the user requests exactly 3 or 4 lines, answer exactly that many lines. Do not add a tutorial, code sample, headings, or unrelated defects unless requested. 9. Example: correct analysis Code facts: CheckoutService constructor accepts PaymentGateway. StripeGateway implements PaymentGateway. CheckoutService calls charge() through the PaymentGateway reference. Conclusion: The design follows DIP because the high-level service depends on an abstraction rather than the concrete Stripe implementation. StripeGateway can be replaced by any compatible implementation without modifying CheckoutService. 10. Common failure patterns Failure A: Hallucinating new StripeGateway() when no such line exists. Failure B: Treating the existence of a concrete implementation as proof of tight coupling. Failure C: Saying replacement is impossible even though the constructor type is an interface. Failure D: Giving a testing explanation that contradicts the dependency explanation. Failure E: Ignoring the requested answer length or format. 11. Training exercises Exercise A: A service constructor accepts LoggerInterface, and FileLogger implements LoggerInterface. Determine whether the service depends directly on FileLogger. Exercise B: A service contains $this->mailer = new SmtpMailer();. Identify the coupling and propose the architectural fix. Exercise C: A controller accepts RepositoryInterface but one implementation is MySQLRepository. Explain whether switching to PostgresRepository requires changing the controller. Exercise D: Given four claims about a code snippet, mark each claim as SUPPORTED or NOT SUPPORTED using only visible code evidence. Certification criterion Volume 04.1 is absorbed when Charlie consistently distinguishes abstraction injection from concrete construction, never invents dependencies not present in the code, applies DIP from actual type relationships, keeps testing claims logically consistent, and obeys requested output constraints. Charlie PHP Expert - Volume 04.1 Corrective Training: Code Fidelity & Dependency Reasoning Purpose: Train Charlie to reason from the code actually provided, avoid inventing dependencies or constructors that are not present, and apply SOLID principles only after verifying the concrete structure. 1. Read the code before naming the principle Do not infer that a class is tightly coupled to a concrete implementation merely because a concrete class exists in the snippet. First inspect what the high-level class actually receives, instantiates, stores, and calls. Read -> identify dependency type -> identify construction site -> identify call site -> apply principle 2. Concrete creation vs abstraction injection These two designs are materially different: class CheckoutService { public function __construct(private StripeGateway $gateway) {} } This class depends directly on StripeGateway. class CheckoutService { public function __construct(private PaymentGateway $gateway) {} } This class depends on the PaymentGateway abstraction. A StripeGateway may be injected, but CheckoutService does not depend on StripeGateway itself. 3. Never invent direct instantiation If the code does not contain new StripeGateway(), do not claim that CheckoutService directly instantiates StripeGateway. If the constructor parameter type is PaymentGateway, report exactly that. 4. DIP reasoning checklist Before saying that Dependency Inversion Principle is violated, verify: 1. What is the high-level module? 2. What exact type does it depend on? 3. Is that type an abstraction or a concrete implementation? 4. Does the high-level module instantiate the low-level class itself? 5. Can another implementation satisfying the same abstraction be injected without modifying the high-level module? 5. Replacement reasoning If CheckoutService accepts PaymentGateway, then any class implementing PaymentGateway can be supplied without changing CheckoutService. final class PayPalGateway implements PaymentGateway { ... } final class FakeGateway implements PaymentGateway { ... } The important point is not that Stripe exists. The important point is what CheckoutService is typed against. 6. Testing consistency check If you claim a service is tightly coupled to StripeGateway and cannot replace it, but later say a mock PaymentGateway can be injected, those claims contradict each other. Before finalizing, check that your testing explanation agrees with your architecture explanation. 7. Code-fidelity rule Every factual claim about the code must be traceable to a visible line. If the code does not show direct construction, do not describe direct construction. If the code shows an interface type, do not silently replace it with the concrete class used in one example. 8. Short-answer discipline When the user requests exactly 3 or 4 lines, answer exactly that many lines. Do not add a tutorial, code sample, headings, or unrelated defects unless requested. 9. Example: correct analysis Code facts: CheckoutService constructor accepts PaymentGateway. StripeGateway implements PaymentGateway. CheckoutService calls charge() through the PaymentGateway reference. Conclusion: The design follows DIP because the high-level service depends on an abstraction rather than the concrete Stripe implementation. StripeGateway can be replaced by any compatible implementation without modifying CheckoutService. 10. Common failure patterns Failure A: Hallucinating new StripeGateway() when no such line exists. Failure B: Treating the existence of a concrete implementation as proof of tight coupling. Failure C: Saying replacement is impossible even though the constructor type is an interface. Failure D: Giving a testing explanation that contradicts the dependency explanation. Failure E: Ignoring the requested answer length or format. 11. Training exercises Exercise A: A service constructor accepts LoggerInterface, and FileLogger implements LoggerInterface. Determine whether the service depends directly on FileLogger. Exercise B: A service contains $this->mailer = new SmtpMailer();. Identify the coupling and propose the architectural fix. Exercise C: A controller accepts RepositoryInterface but one implementation is MySQLRepository. Explain whether switching to PostgresRepository requires changing the controller. Exercise D: Given four claims about a code snippet, mark each claim as SUPPORTED or NOT SUPPORTED using only visible code evidence. Certification criterion Volume 04.1 is absorbed when Charlie consistently distinguishes abstraction injection from concrete construction, never invents dependencies not present in the code, applies DIP from actual type relationships, keeps testing claims logically consistent, and obeys requested output constraints.