Constructores

 <?php

        class A {

            public $elementos = [];

            public function __construct() {
                for ($i = 0; $i < 10; $i++) {
                    $this->elementos[] = $i;
                }
            }
          

        }

        class B {

            public $elementos = [];

            public function __construct($num=10) {
                for ($i = 0; $i < $num; $i++) {
                    $this->elementos[] = $i;
                }
            }

        }

        $a = new A();
        $b = new A();


        $c = new B(3);
        $d = new B(9);
        $e = new B();

        print_r($c->elementos);
        print_r($d->elementos);
        print_r($e->elementos);
        ?>

Herencia y visibilidad

 <?php

        class A {

            public $aa = "aa";
            private $bb = "bb";
            protected $cc = "cc";

        }

        class B extends A {

            public $dd = "dd";
            private $ee = "ee";

            function test() {
                echo $this->aa;
                echo $this->bb; //Esta no la imprime
                echo $this->cc;
                echo $this->dd;
                echo $this->ee;
            }

        }

        $obj = new B();
        $obj->test();

        echo $obj->aa;
        echo $obj->bb;//Esta no la imprime
        echo $obj->cc;//Esta no la imprime
        echo $obj->dd;
        echo $obj->ee;//Esta no la imprime

Ejercicio alumnos

class Alumno {

            private $nombre;
            private $nota;
            private $apellidos;

            //Set y get para todas las propiedades. La nota enter 0 y 10
            //El resto no vacíos
            //Función aprobado que nos devuelva true si la nota es >=5
            //Función nombre completo que nos devuelva el nombre y el apellido
            //¿Sería posible hacerlo como propiedad y no como función?
            //Functión mágica toString que nos devuelva nombre completo y nota

            function __set($name, $value) {
                if (property_exists($this, $name)) {
                    if ($name == 'nota') {
                        if ($value >= 0 && $value <= 10) {
                            $this->nota = $value;
                        } else {
                            throw new Exception("La nota debe estar entre 0 y 10");
                        }
                    } else {
                        if (!empty($value)) {
                            $this->$name = $value;
                        }
                    }
                }
            }

            function aprobado() {
                return $this->nota >= 5;
            }

            function __get($name) {
                if (property_exists($this, $name)) {
                    return $this->$name;
                } else {
                    if ($name == "nombreCompleto") {
                        return $this->nombreCompleto();
                    }
                }
            }

            function nombreCompleto() {
                return $this->nombre . " " . $this->apellidos;
            }

            public function __toString() {
                return $this->nombreCompleto." - ".$this->nota;
            }

        }

        $ana = new Alumno();
        $ana->nombre="Ana";
        $ana->apellidos="Pi";
        $ana->nota=7;
        echo $ana->nombreCompleto."<br/>";
        echo $ana;
        ?>

Setters y getters, diferentes formas

Con funciones:

 class Coche{
            private $marca;
            private $modelo;
            private $velocidad;
            
            //Crear las funciones que nos permitan poner y obtener valores
            //En el caso de la velocidad el valor permitido está entre 50 y 300
            //En el caso de marca y modelo comprobar que no esté vacío
            
            function setMarca($marca){
                if (!empty($marca)){
                    $this->marca=$marca;
                }
            }
            function setModelo($modelo){
                if (!empty($modelo)){
                    $this->modelo=$modelo;
                }
            }
            function setVelocidad($velocidad){
                if ($velocidad>=50 && $velocidad<=300){
                    $this->velocidad=$velocidad;
                } else{
                    throw new Exception("La velocidad debe estar entre 50 y 300");
                }
            }
            
            function getMarca(){
                return $this->marca;
            }
            function getModelo(){
                return $this->modelo;
            }
            function getVelocidad(){
                return $this->velocidad;
            }
        }
        
        $seat=new Coche();
        $seat->setMarca("Seat");
        $seat->setModelo("Panda");
        $seat->setVelocidad(180);
        print_r($seat);

Con __get y __set

     <?php
        class Coche {

            private $marca;
            private $modelo;
            private $velocidad;

            //Crear las funciones que nos permitan poner y obtener valores
            //En el caso de la velocidad el valor permitido está entre 50 y 300
            //En el caso de marca y modelo comprobar que no esté vacío

            function __get($name) {
                if (property_exists('Coche', $name)) {
                    return $this->$name;
                }
            }

            function __set($name, $value) {
                if ($name == "velocidad") {
                    if ($value >= 50 && $value <= 300) {
                        $this->velocidad = $value;
                    } else {
                        throw new Exception("La velocidad debe estar entre 50 y 300");
                    }
                } else {
                    if (!empty($value) && property_exists('Coche', $name)) {
                        $this->$name = $value;
                    }
                }
            }

        }

        $seat = new Coche();
        $seat->marca = "Seat";
        $seat->modelo = "Panda";
        $seat->velocidad = 180;
        $seat->color="rojo";
        echo $seat->modelo;
        echo $seat->color;
        print_r($seat);

Páginas web Scrapping

Por ejemplo, wikipedia:

https://es.wikipedia.org/w/index.php?title=Categor%C3%ADa:Actores_de_Espa%C3%B1a&from=A

https://es.wikipedia.org/wiki/Categor%C3%ADa:Actores_de_Estados_Unidos

O las páginas amarillas:

https://www.paginasamarillas.es

(Recordemos que tenemos el script aquí: http://trifulcas.com/web-scrapping-paginas-amarillas/)

Flickr:

https://www.flickr.com/search/?text=pallet%20upcycling

Gimnasios:

http://www.gimcat.com/clubs.html?provincia=08&id=38

http://www.gametronik.com/site/index.php

Trivial 2.0: Completo

libreria.php

<?php

function conectar() {
    $server = "localhost";
    $user = "root";
    $password = "";
    $db = "trivial";
    try {
        $conn = new PDO("mysql:host=$server;dbname=$db", $user, $password, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"]);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $conn;
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

function getPregunta($idUsuario) {
    try {
        $conn = conectar();
        //Buscamos una pregunta que no se haya hecho a este usuario al azar
        $sql = "SELECT * FROM preguntas where idpreguntas not in (select idpreguntas from resultados where idusuarios=$idUsuario) order by rand() limit 1";
        $resul = $conn->query($sql);
        $fila = $resul->fetch();
        return $fila;
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

function getPuntuacion($idUsuario) {
    try {
        $conn = conectar();
        $sql = "SELECT ifnull(sum(puntos),0) puntuacion FROM resultados where idusuarios=:id";
        $st = $conn->prepare($sql);
        $st->execute(['id' => $idUsuario]);
        $fila = $st->fetch();
        return $fila['puntuacion'];
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

function comprobarUsuario($nombre, $password) {
    try {
        $conn = conectar();
        //Buscamos un usuario con el nombre solicitado
        $sql = "select * from usuarios where nombre=:nombre";
        $st = $conn->prepare($sql);
        $st->execute(['nombre' => $nombre]);
        $usuario = $st->fetch();
        //Si no existe es un alta, lo insertamos en la BD
        if (!$usuario) {
            $st = $conn->prepare("insert into usuarios (nombre,password) values (:nombre,:password)");
            $st->execute(['nombre' => $nombre, 'password' => md5($password)]);
            //Y devolvemos el id del usuario insertado
            return $conn->lastInsertId();
        } else {
            //Si el usuario existe miramos si la contrasela coincide, si es así devolvemos el id
            if (md5($password) == $usuario['password']) {
                return $usuario['idusuarios'];
            }
        }
        //Si no se da ninguna de las condiciones devolvemos falso
        return false;
    } catch (Exception $ex) {
        echo $ex->getMessage();
        return false;
    }
}

function guardaResultado($idUsuario, $idPregunta, $puntos) {
    try {
        $conn = conectar();
        $sql = "insert into resultados (idusuarios,idpreguntas,puntos) values (:idu,:idp,:puntos)";
        $st = $conn->prepare($sql);
        $st->execute(['idu' => $idUsuario, 'idp' => $idPregunta, 'puntos' => $puntos]);
        return getPuntuacion($idUsuario);
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

login.php

<?php
require_once 'libreria.php';
$error="";
session_start();
//Recuperamos el valor de nombre y password
$nombre= filter_input(INPUT_POST, 'nombre');
$password= filter_input(INPUT_POST, 'password');

//Si no están vacíos es porque hay un registro o login, lo comprobamos en la BD
if (!empty($nombre) && !empty($password)){
    //La función comprobar Usuario nos devuelve el id del usuario si existe
    $idUsuario=comprobarUsuario($nombre,$password);
    //Si existe el usuario guardamos la información en la BD y redirigimos al index
    if ($idUsuario){
        $_SESSION['idUsuario']=$idUsuario;
        $_SESSION['nombre']=$nombre;
        header("location:index.php");
    } else{
        $error="Usuario o contraseña incorrecta";
    }
}
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Trivial informático</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>

        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>

    </head>
    <body>
        <div class="container" >
            <div class="jumbotron">
            <h1>Introduce tu usuario y contraseña</h1>
            <h2>Si no estás en el sistema se creará tu usuario</h2>
            <h2 class="text-danger"><?=$error?></h2>
            </div>
            <form method="post">
                <div class="form-group">
                    <label for="nombre">Usuario:</label>
                    <input type="text" class="form-control" name="nombre">
                </div>
                <div class="form-group">
                    <label for="pwd">Password:</label>
                    <input type="password" class="form-control" name="password">
                </div>
                <button type="submit" class="btn btn-primary">Enviar</button>
            </form>
        </div>
    </body>
</html>

index.php

<?php
session_start();
//Si no está definida la variable de sesión es que no se ha logueado, lo mandamos al login
if (empty($_SESSION['idUsuario'])){
    header("location:login.php");
}
require_once("libreria.php");
//Recuperamos la puntuación para mostrarla
$puntuacion= getPuntuacion($_SESSION['idUsuario']);
?>
<!DOCTYPE html>

<html>
    <head>
        <title>Trivial informático</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>

        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
        
    </head>
    <body>
        <div class="container" >
            <div class="jumbotron">
                <h1 class="display-1">Trivial. Bienvenido <?=$_SESSION['nombre']?></h1>
                <p>¿Cual es tu cultura general? Puntuación: <span id="puntuacion"><?=$puntuacion?></span></p>
            </div>
            <div class="row">
                <div class="col-12" id="mensaje" style="min-height: 70px;"></div>
            </div>
            <div class="row tablero">
                <div class="col-12"><h1 id="pregunta" class="text-center">Bienvenido al trivial. Muy pronto preguntas</h1></div>
            </div>
            <div class="row my-4 tablero">

                <div class="col-6 text-center"><button id="res1" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res2" class="btn btn-lg btn-success">.</button></div>

            </div>

            <div class="row tablero">

                <div class="col-6 text-center"><button id="res3" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res4" class="btn btn-lg btn-success">.</button></div>

            </div>
        </div>
        <script src="trivial.js" type="text/javascript"></script>

    </body>
</html>

trivial.js

var preguntas;
//Busca una pregunta por Ajax
function cargarPregunta() {
    $.get("pregunta.php", function (datos, status) {

        if (status == "success") {
            preguntas = JSON.parse(datos);
            pintarPregunta();
        }
    });
}
//Pinta la pregunta en nuestro HTML
function pintarPregunta() {
    $('#pregunta').text(preguntas.pregunta);
    $('#res1').text(preguntas.respuestas[0]);
    $('#res2').text(preguntas.respuestas[1]);
    $('#res3').text(preguntas.respuestas[2]);
    $('#res4').text(preguntas.respuestas[3]);
    $(".tablero").show();
    $('#mensaje div').fadeOut();
}

$(function () {
    cargarPregunta();
    //Enlazar con los botones el evento click y comprobar si la respuesta es correcta
    $('button').click(function () {
        var puntos = 0;
        //Comprobamos que el botón pulsado es la respuesta correcta
        if ($(this).text() === preguntas.correcta) {
            $('#mensaje').html('<div class="alert alert-success alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Bien! </strong> Respuesta correcta.</div>')
            puntos = 1;
        } else {
            $('#mensaje').html('<div class="alert alert-danger alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Error! </strong> Respuesta incorrecta.</div>')

        }
        //Escondemos el tablero para queno pueda pulsar más botones
        $(".tablero").hide();
        //LLamamos por ajax con post para guardar los resultados, la función nos devuelve la puntuación
        $.post("resultado.php", {idPregunta: preguntas.id, puntos: puntos}, function (datos, status) {
            $('#puntuacion').text(datos);
            cargarPregunta();
        });

    });
});

pregunta.php

<?php

require_once 'libreria.php';
session_start();
//Obtenemos una pregunta de la base de datos
$fila = getPregunta($_SESSION['idUsuario']);

//La fila que recuperamos la organizamos de una manera más amigable para el JS
$res['pregunta'] = $fila['pregunta'];
$res['id'] = $fila['idpreguntas'];
$res['correcta'] = $fila['respuesta1'];
$res['respuestas'] = [$fila['respuesta1'], $fila['respuesta2'], $fila['respuesta3'], $fila['respuesta4']];
shuffle($res['respuestas']);

//Lo codificamos en JSON
echo json_encode($res);

resultado.php

<?php
require_once 'libreria.php';
session_start();
//Recuperamos los datos
$idUsuario= $_SESSION['idUsuario'];
$idPregunta= filter_input(INPUT_POST, 'idPregunta');
$puntos= filter_input(INPUT_POST, 'puntos');
//Y guardamos el resultado
$puntos=guardaResultado($idUsuario,$idPregunta,$puntos);
//Devolvemos los puntos
echo $puntos;

Trivial 2.0: Responder pregunta

Cuando el usuario pinche en un botón tendremos que averiguar si la respuesta es correcta y guardar el resultado de la acción en la base de datos. Es más sencillo de lo que parece. En primer lugar enlazamos el click de los botones por jQuery:

  $('button').click(function () {
....
}

Ahí tendremos que hacer dos cosas. Comprobar que la respuesta es correcta o no y mostrar un mensaje en consecuencia y guardar en la base de datos. Lo primero es simple:

 var puntos = 0;
        if ($(this).text() === preguntas.correcta) {
            $('#mensaje').html('<div class="alert alert-success alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Bien! </strong> Respuesta correcta.</div>')
            puntos = 1;
        } else {
            $('#mensaje').html('<div class="alert alert-danger alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Error! </strong> Respuesta incorrecta.</div>')

        }

Lo segundo, también:

$.post("resultado.php", {idPregunta: preguntas.id, puntos: puntos}, function (datos, status) {
            $('#puntuacion').text(datos);
            cargarPregunta();
        });

Todo junto:

 $('button').click(function () {
        var puntos = 0;
        //Comprobamos que el botón pulsado es la respuesta correcta
        if ($(this).text() === preguntas.correcta) {
            $('#mensaje').html('<div class="alert alert-success alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Bien! </strong> Respuesta correcta.</div>')
            puntos = 1;
        } else {
            $('#mensaje').html('<div class="alert alert-danger alert-dismissible">  <button type="button" class="close" data-dismiss="alert">&times;</button>  <strong>¡Error! </strong> Respuesta incorrecta.</div>')

        }
        //Escondemos el tablero para queno pueda pulsar más botones
        $(".tablero").hide();
        //LLamamos por ajax con post para guardar los resultados, la función nos devuelve la puntuación
        $.post("resultado.php", {idPregunta: preguntas.id, puntos: puntos}, function (datos, status) {
            $('#puntuacion').text(datos);
            cargarPregunta();
        });

    });

La página a la que llamamos se limita a guardar los datos y devolver la puntuación:

<?php
require_once 'libreria.php';
session_start();
//Recuperamos los datos
$idUsuario= $_SESSION['idUsuario'];
$idPregunta= filter_input(INPUT_POST, 'idPregunta');
$puntos= filter_input(INPUT_POST, 'puntos');
//Y guardamos el resultado
$puntos=guardaResultado($idUsuario,$idPregunta,$puntos);
//Devolvemos los puntos
echo $puntos;

Guardar resultado es un simple insert:

function guardaResultado($idUsuario, $idPregunta, $puntos) {
    try {
        $conn = conectar();
        $sql = "insert into resultados (idusuarios,idpreguntas,puntos) values (:idu,:idp,:puntos)";
        $st = $conn->prepare($sql);
        $st->execute(['idu' => $idUsuario, 'idp' => $idPregunta, 'puntos' => $puntos]);
        return getPuntuacion($idUsuario);
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Y obtener los resultados un simple sql:

function getPuntuacion($idUsuario) {
    try {
        $conn = conectar();
        $sql = "SELECT ifnull(sum(puntos),0) puntuacion FROM resultados where idusuarios=:id";
        $st = $conn->prepare($sql);
        $st->execute(['id' => $idUsuario]);
        $fila = $st->fetch();
        return $fila['puntuacion'];
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Trivial 2.0: Recuperar pregunta por ajax

Para recuperar las preguntas por ajax necesitamos tres cosas. Una llamada con ajax desde JS. Una página en PHP que busque la pregunta y la devuelva. Y, como somos ordenaditos, una función en la librería que busque la pregunta.

Empecemos por el JS, que se limita a pedir la pregunta:

var preguntas;
//Busca una pregunta por Ajax
function cargarPregunta() {
    $.get("pregunta.php", function (datos, status) {

        if (status == "success") {
            preguntas = JSON.parse(datos);
            pintarPregunta();
        }
    });
}
//Pinta la pregunta en nuestro HTML
function pintarPregunta() {
    $('#pregunta').text(preguntas.pregunta);
    $('#res1').text(preguntas.respuestas[0]);
    $('#res2').text(preguntas.respuestas[1]);
    $('#res3').text(preguntas.respuestas[2]);
    $('#res4').text(preguntas.respuestas[3]);
    $(".tablero").show();
    $('#mensaje div').fadeOut();
}

El backend en php, donde llama el ajax, es sólo un poco más complicado:

<?php

require_once 'libreria.php';
session_start();
//Obtenemos una pregunta de la base de datos
$fila = getPregunta($_SESSION['idUsuario']);

//La fila que recuperamos la organizamos de una manera más amigable para el JS
$res['pregunta'] = $fila['pregunta'];
$res['id'] = $fila['idpreguntas'];
$res['correcta'] = $fila['respuesta1'];
$res['respuestas'] = [$fila['respuesta1'], $fila['respuesta2'], $fila['respuesta3'], $fila['respuesta4']];
shuffle($res['respuestas']);

//Lo codificamos en JSON
echo json_encode($res);

Por último necesitamos en nuestra librería una función que nos busque una pregunta en la BD y nos la devuelva:

function getPregunta($idUsuario) {
    try {
        $conn = conectar();
        //Buscamos una pregunta que no se haya hecho a este usuario al azar
   $sql = "SELECT * FROM trivial.preguntas where idpreguntas not in (select idpreguntas from resultados where idusuarios=$idUsuario) order by rand() limit 1";
            $resul = $conn->query($sql);
        $fila = $resul->fetch();
        return $fila;
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
}

Trivial 2.0: Página de juego

Lo primero que tendremos en nuestra página de juego es una comprobación de que el usuario se haya logueado:

<?php
session_start();
//Si no está definida la variable de sesión es que no se ha logueado, lo mandamos al login
if (empty($_SESSION['idUsuario'])){
    header("location:login.php");
}
require_once("libreria.php");
//Recuperamos la puntuación para mostrarla
$puntuacion= getPuntuacion($_SESSION['idUsuario']);
?>

De paso recuperamos la puntuación (lo veremos más adelante).

La página de juego es una página muy sencilla con sólo html. La mecánica del juego la tenemos en el javascript. Puede ser algo como esto:

 <div class="container" >
            <div class="jumbotron">
                <h1 class="display-1">Trivial. Bienvenido <?=$_SESSION['nombre']?></h1>
                <p>¿Cual es tu cultura general? Puntuación: <span id="puntuacion"><?=$puntuacion?></span></p>
            </div>
            <div class="row">
                <div class="col-12" id="mensaje" style="min-height: 70px;"></div>
            </div>
            <div class="row tablero">
                <div class="col-12"><h1 id="pregunta" class="text-center">Bienvenido al trivial. Muy pronto preguntas</h1></div>
            </div>
            <div class="row my-4 tablero">

                <div class="col-6 text-center"><button id="res1" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res2" class="btn btn-lg btn-success">.</button></div>

            </div>

            <div class="row tablero">

                <div class="col-6 text-center"><button id="res3" class="btn btn-lg btn-success">.</button></div>
                <div class="col-6 text-center"><button id="res4" class="btn btn-lg btn-success">.</button></div>

            </div>
        </div>
        <script src="trivial.js" type="text/javascript"></script>